列表段视图何时完全夸大?上下文动作栏问题



我正在编写新的Android活动,并且在ListFragment上遇到麻烦。这里的想法是,父活动托管了一个ListFragment,其数据是使用适配器从数据库中提取的。当调用上下文操作栏(CAB)时,CheckBox项目(这是ListView托管的CC_4中每一行的布局的一部分)将变得可见。默认情况下,CheckBox项目不可见。CheckBox项目在我的MultiChoiceModeListener类中检查onItemCheckedStateChanged()方法。

我的目标是在屏幕方向更改时保留复选框的状态。

随激活CAB的方向更改时,ListView的每一行(由ListFragment托管)中的复选框项目变得不可见。我认为这是因为ListFragment通过onCreateView()回调重新绘制。

但是,我的问题是,在试图重新启用复选框时,我会得到无效的指针异常。何时访问片段中的行视图元素?如果我等待很长时间(即,在onItemCheckedStateChanged()内重新启用,这不是理想的选择,因为我不想重新单击所有内容!),可以访问并将复选框设置为可见。如果我尝试从较早的片段(例如在onCreateView()onViewCreated()中)访问它,则复选框项目为null,但行视图的其余部分不是null。

有什么建议吗?这是一些代码:

null指针异常在restoreSelectedCheckBoxes()内抛出。这些行在下面确定。

来自父级Activity

// In the parent activity. Called from onCreate()
private void displayListViewTEMP() {
    // add fragment to apropriate layout item, but do not overwrite!
    FragmentTransaction fTrans;
    FragmentManager fMan = getFragmentManager();
    // fragContainer is null until something is added to it
    if (fMan.findFragmentByTag(Activity_Home.NAME_LIST_FRAG_TAG) == null) {
        Log.i(TAG, "Adding fragment to feed_list_container");
        fTrans = fMan.beginTransaction();
        fTrans.add(R.id.feed_list_container, new Name_List(), Activity_Home.NAME_LIST_FRAG_TAG);
        fTrans.commit();
    }
}

来自ListFragment

// this is the method I call to restore the checkboxes
public void restoreSelectedCheckBoxes() {
    Log.i(TAG, "restoring selected button state");
    ListView v = getListView();
    // this variable holds the indices of selected items in the list
    int selCnt = selectedListItems.size();
    CheckBox bx;
    for (int i = 0; i < selCnt; i++) {
        Log.i(TAG, "v = " + v);             <-- prints valid oref
        bx = (CheckBox) v.findViewById(R.id.item_checkbox);
        Log.i(TAG, "bx = " + bx);           <-- prints 'null' after orientation change
        bx.setChecked(true);                <-- NULL pointer exception
    }
}

这是我用来设置CAB的数据:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    // omitted code to set up adapter
    ListView listView = getListView();
    listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
    listView.setMultiChoiceModeListener(getChoiceListener());
}
// set up contextual action bar
private MultiChoiceModeListener getChoiceListener() {
    if (this.choiceListener != null)
        return this.choiceListener;
    this.choiceListener = new MultiChoiceModeListener() {
        @Override
        // Inflate the menu for the CAB
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            Log.i(TAG, "Creating contextual action bar");
            MenuInflater inflater = mode.getMenuInflater();
            inflater.inflate(R.menu.main_name_context, menu);
            ListView v = getListView();
            int vCnt = v.getCount();
            View child;
            CheckBox bx; 
            // set checkbox subviews as visible
            for (int i = 0; i < vCnt; i++) {
                child = v.getChildAt(i);
                if (child == null)
                    continue;
                bx = (CheckBox) child.findViewById(R.id.item_checkbox);
                bx.setVisibility(View.VISIBLE);
            }
            return true;
        }
        // omitted other overridden methods that aren't relevant        
    };
    return this.choiceListener;
}

*非常感谢您的帮助!解决方案确实是按建议覆盖适配器。请参阅最终代码: *

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = super.getView(position, convertView, parent);
    if (selectedListItems.contains(position)) {
        CheckBox bx = (CheckBox) v.findViewById(R.id.item_checkbox);
        bx.setVisibility(View.VISIBLE);
        bx.setChecked(true);
    }
    return v;
}

您使用哪种适配器用于列表fragment?

我将通过扩展ArrayAdapter(或您现在使用的任何内容)来创建一个适配器类,并将状态恢复逻辑添加到Adapter.getView()方法,而不是试图等待等待您的视图,直到您的视图完成了布局,等。

如果您不确定如何扩展ArrayAdapter,请参阅这篇文章:如何使我的ArrayAdapter遵循视图持有人模式?

尝试以下:

getView().post(new Runnable() {
    @Override
    public void run() {
        // code you want to run when view is visible/inflated for the first time
    }
 }
);

最新更新