我有一个ExpandableListView,其中每一行包含一个CheckBox和一个TextView。当组扩展时,我需要根据从sqlite数据库中提取的数据初始化每个复选框(并存储在ArrayList中)。我有阵列表。这很容易。
我无法做的是获取每个复选框的句柄。现在,现在我的工作很重要,当我尝试引用其中的任何一个时,我继续得到空指针错误。这是我的代码(在我的onCreate方法中用于活动):
expandableList.setOnGroupClickListener(new OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPostition, long id) {
//this initializes to 0
int i = expandableList.getLastVisiblePosition() - expandableList.getFirstVisiblePosition();
for (MySettings thisSetting : settingsList) {
System.err.println(i);
View view = parent.getChildAt(i);
CheckBox checkBox = (CheckBox) view.findViewById(R.id.check_box); //<--null pointer error
System.err.println(thisSetting.getIsSelected());
checkBox.setChecked(thisSetting.getIsSelected());
i++;
}
return false;
}
});
我在声明checkBox变量的行上得到空指针错误。我使用几乎相同的代码来处理onChildClick事件,所以我不明白这是如何不同的。谢谢你的帮助。如果您需要其他代码,请与我们联系。
答案 0 :(得分:1)
我会尝试解释我在申请时的方式。
首先,您必须创建自己的自定义适配器,以便使用列表,数组或您使用的任何内容初始化列表:
public class CustomELVAdapter extends BaseExpandableListAdapter {
private LayoutInflater mInflater;
private ArrayList<AttributeFilter> mParent;//List containing the groups to display
public CustomELVAdapter(Context context, ArrayList<AttributeFilter> parent){
mParent = parent;
mInflater = LayoutInflater.from(context);
}
@Override
//counts the number of groups in the exapndable list
public int getGroupCount() {
return mParent.size();
}
@Override
//counts the number of children items contained in a specific group
public int getChildrenCount(int groupPosition) {
return mParent.get(groupPosition).getArrayChildren().size();
}
@Override
//gets the title ofa group
public Object getGroup(int groupPosition) {
return mParent.get(groupPosition).getTitle();
}
@Override
//gets a child object in a group
public Object getChild(int groupPosition, int childPosition) {
//return mParent.get(groupPosition).getArrayChildren().get(childPosition);
return mParent.get(groupPosition).getArrayChildren().valueAt(childPosition);
}
@Override
public long getGroupId(int i) {
return i;
}
@Override
public long getChildId(int i, int i1) {
return i1;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
//in this method you must set the text to see the parent/group on the list
public View getGroupView(int groupPosition, boolean b, View view, ViewGroup viewGroup) {
if (view == null) {
view = mInflater.inflate(R.layout.filter_list_parent, viewGroup,false);
}
TextView textView = (TextView) view.findViewById(R.id.filter_list_parent_textview);
TextView detailsTV = (TextView) view.findViewById(R.id.filter_list_parent_details);
Object parentObject = mParent.get(groupPosition);
AttributeFilter attributeFilter = (AttributeFilter) parentObject;
//"i" is the position of the parent/group in the list
textView.setText(getGroup(groupPosition).toString());
detailsTV.setText(attributeFilter.getDetails());
//return the entire view
return view;
}
@Override
//set a child in a group
public View getChildView(int groupPosition, int childPosition, boolean b, View view, ViewGroup viewGroup) {
ViewHolder holder;
if (view == null) {
view = mInflater.inflate(R.layout.filter_list_child, viewGroup,false);
holder = new ViewHolder();
//holder.imageView = (ImageView) view.findViewById(R.id.filter_list_child_imageview);
holder.checkbox = (CheckBox) view.findViewById(R.id.filter_list_child_checkbox);
holder.title = (TextView) view.findViewById(R.id.filter_list_child_textview);
view.setTag(holder);
}
else {
holder = (ViewHolder) view.getTag();
}
try {
Attribute attribute = mParent.get(groupPosition).getArrayChildren().valueAt(childPosition);
holder.checkbox.setChecked(attribute.isSelected());
holder.title.setText(attribute.getName());
view.setTag(R.string.filter_attribute_id, attribute.getID());
} catch (Exception e) {
Log.e(RateDayApplication.LOG_ERROR,"CustomELVAdapter - getChildView - attribute is null");
}
//return the entire view
return view;
}
@Override
public boolean isChildSelectable(int i, int i1) {
return true;
}
@Override
public void registerDataSetObserver(DataSetObserver observer) {
/* used to make the notifyDataSetChanged() method work */
super.registerDataSetObserver(observer);
}
static class ViewHolder {
CheckBox checkbox;
TextView title;
//ImageView icon; NOT NEEDED YET
}
}
在我的示例中,mParent
中的孩子都包含在SparseArray
中,这对我来说很方便,因为我需要访问具有特定ID的孩子,而不仅仅是一个位置。但在你的情况下你当然可以做任何事情,如果你使用列表例如你必须修改代码以valueAt
修改get
(valueAt
是一个可用的函数对于SparseArrays而不是列表)。
完成此适配器后,您必须在活动中准备要提供的数据。在我的情况下,我有3组(固定)都包含不同数量的孩子:
ArrayList<AttributeFilter> arrayParents = new ArrayList<AttributeFilter>();//Initialize of the parents array that will be provided to the adapter.
//Preparation of the first group (AttributeFilter is a custom type I created holding the `SparseArray` with the children and the group title)
AttributeFilter categoriesFilter = new AttributeFilter();
categoriesFilter.setTitle(getResources().getString(R.string.categories));
categoriesFilter.setDetails(Tools.getLabelsStringFromSparseArray(categoriesSparseArray, prefs.getCategories()));
categoriesSparseArray = Tools.initializeSparseArray(categoriesSparseArray, prefs.getCategories());
categoriesFilter.setArrayChildren(categoriesSparseArray);
//Preparation of the second group
AttributeFilter emotionsFilter = new AttributeFilter();
emotionsFilter.setTitle(getResources().getString(R.string.emotions));
emotionsFilter.setDetails(Tools.getLabelsStringFromSparseArray(emotionsSparseArray, prefs.getEmotions()));
emotionsSparseArray = Tools.initializeSparseArray(emotionsSparseArray, prefs.getEmotions());
emotionsFilter.setArrayChildren(emotionsSparseArray);
//Preparation of the third group
AttributeFilter ratingsFilter = new AttributeFilter();
ratingsFilter.setTitle(getResources().getString(R.string.ratings));
ratingsFilter.setDetails(Tools.getLabelsStringFromSparseArray(ratingsSparseArray, prefs.getRatings()));
ratingsSparseArray = Tools.initializeSparseArray(ratingsSparseArray, prefs.getRatings());
ratingsFilter.setArrayChildren(ratingsSparseArray);
//in this array we add the Parent object. We will use the arrayParents at the setAdapter
arrayParents.add(categoriesFilter);
arrayParents.add(emotionsFilter);
arrayParents.add(ratingsFilter);
//sets the adapter that provides data to the list.
filtersELV.setAdapter(new CustomELVAdapter(this,arrayParents));//the adapter is applied on my `ExpandableListView`.
以下是自定义类型定义FilterAttribute
(FYI):
public class AttributeFilter {
private String mTitle;
private String mDetails;
private SparseArray<Attribute> mArrayChildren;
public String getTitle() {
return mTitle;
}
public void setTitle(String mTitle) {
this.mTitle = mTitle;
}
public String getDetails() {
return mDetails;
}
public void setDetails(String mDetails) {
this.mDetails = mDetails;
}
public SparseArray<Attribute> getArrayChildren() {
return mArrayChildren;
}
public void setArrayChildren(SparseArray<Attribute> mArrayChildren) {
this.mArrayChildren = mArrayChildren;
}
}
以防万一,班级Attribute
:
public class Attribute {
private int id;
private String name;
private boolean selected;
private int drawableID;
// constructor
public Attribute(int _id, String _name, int _drawable_id, boolean _selected){
id = _id;
name = _name;
drawableID = _drawable_id;
selected = _selected;
}
public int getID() {
return id;
}
public void setID(int _id) {
this.id = _id;
}
public String getName() {
return name;
}
public void setName(String _name) {
this.name = _name;
}
public int getDrawableID() {
return drawableID;
}
public void setDrawableID(int _drawable_id) {
this.drawableID = _drawable_id;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean _selected) {
this.selected = _selected;
}
}
对于布局重要的一件事,您必须将复选框设置为不可聚焦,否则您将永远无法使复选框切换工作:
<?xml version="1.0" encoding="utf-8"?>
<CheckBox android:id="@+id/filter_list_child_checkbox"
android:focusable="false"
android:focusableInTouchMode="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/filter_list_child_textview"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:padding="10dp"
android:layout_weight="1" />
我希望消化不太难