我正在编写新的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
}
}
);