我有一个 ExpandableListView。每个孩子都有一个 CheckBox 和一个 TextView。当用户点击子行时,CheckBox 应该改变其状态(选中与未选中)。如果用户直接点击复选框,这将正常工作。但是,如果用户点击文本视图(同一行,紧邻复选框的右侧),我会在尝试引用复选框时立即收到空指针错误。任何人都可以看到有什么问题吗?
编辑:阅读下面的建议后,我做了一些调查,并意识到我可以在 getChildView() 下的适配器内实现我的 clickListener。这解决了我的空指针问题,因为我可以轻松获得对子视图的引用。
但是,它产生了另一个我认为没有优雅解决方案的问题。每次单击孩子时,我都需要更改列表视图本身。此列表的数据位于 ArrayList 中,其范围在 Activity 内(而不是在 Adapter 中)。如果我的 clickListener 在 Adapter 中,如何回调 Activity 以更改 ArrayList?
这让我觉得是第 22 条规则。如果我希望能够操作我的数据,我无法获得对子视图的引用。但是如果我想引用我的子视图,我的数据超出了范围,所以我无法操作它。人们如何解决这个问题?我肯定错过了什么。
我将输入相关的适配器代码,您可以在其中看到我尝试添加子 onClickListener 的开始。
再次感谢!
public class Settings extends Activity {
//this is the list I need to access from the adapter if my click listener is there
private ArrayList<Categories> categoriesList = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_smart_settings);
db = new EventsDB(this);
expListGroups = new ArrayList<ExpandListGroup>();
setGroups();
/* Set up the data adapter */
expAdapter = new ExpandListAdapter(Settings.this, expListGroups);
populateExpandableGroups();
}
public void setGroups() {
/* Create lists of the individual line items */
categoriesList = db.getCategoriesForClient(client);
locationsList = db.getLocationsForClient(client);
/* Add an item to the locations list to allow the user to add a new location */
locationsList.add(new ClientSmartFinderLocations(client, "Add Location", null, false));
ExpandListGroup categoryGroup = new ExpandListCategory("Choose Categories", categoriesList);
ExpandListGroup locationGroup = new ExpandListLocation("Choose Locations", locationsList);
expListGroups.add(categoryGroup);
expListGroups.add(locationGroup);
}
private void populateExpandableGroups() {
expandableList = (ExpandableListView) findViewById(R.id.expandable_list);
expandableList.setAdapter(expAdapter);
//I've removed this section and moved it to the adapter, per my edit above
// expandableList.setOnChildClickListener(new OnChildClickListener() {
//
// @Override
// public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
//
// /* Update the finder setting for this client */
// String category = categoriesList.get(childPosition).getCategory();
// Boolean isSelected = !categoriesList.get(childPosition).getIsSelected();
// db.setClientCategory(client, category, isSelected);
//
// /* Update the check box to provide feedback to the user */
// View view = parent.getChildAt(childPosition - parent.getFirstVisiblePosition() + 1);
// CheckBox checkBox = (CheckBox) view.findViewById(R.id.check_box);
//
// //error occurs here
// checkBox.setChecked(!checkBox.isChecked());
// return true;
// }
// });
expAdapter.notifyDataSetChanged();
}
public class ExpandListAdapter extends BaseExpandableListAdapter {
//other methods
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view, final ViewGroup parent) {
view = getCategoryChildView(groupPosition, childPosition, view);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TextView tv = (TextView) v.findViewById(R.id.expand_list_item);
CheckBox checkBox = (CheckBox) v.findViewById(R.id.check_box);
String category = tv.getText().toString();
Boolean isSelected = !checkBox.isSelected();
db = new EventsDB(context);
db.setClientCategory(client, category, isSelected);
checkBox.setChecked(!checkBox.isChecked());
//here I need to do some things that require me to manipulate the categoriesList from the Activity class - but it is out of scope
}
});
return view;
}
}
<CheckBox
android:id="@+id/check_box"
android:layout_marginLeft="30dp"
android:focusable="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/expand_list_item"
android:paddingLeft="10dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="@dimen/smart_finder_settings_font_size"
android:textColor="#FFFFFF" />