2013-06-04 35 views
0

我有一个ExpandableListView,其中每行包含一个CheckBox和一个TextView。当组展开时,我需要根据从sqlite数据库中提取的数据(并存储在ArrayList中)初始化每个复选框。我有数组列表。这很容易。初始化ExpandableListView中的复选框

我无法做的是得到每个这些复选框的句柄。现在,现在重要的是我做了什么,当我尝试引用它们中的任何一个时,我仍然会收到空指针错误。这里是我的代码(这是我的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; 
    } 

}); 

我得到的,我声明复选框变量的行空指针错误。我使用几乎相同的代码来处理onChildClick事件,所以我不明白这是如何不同。谢谢你的帮助。让我知道你是否需要额外的代码。

回答

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修改代码getvalueAt是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(仅供参考):

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" /> 

我希望这不是太难以消化

+0

我不是在谈论处理项目的点击。这是为了在用户点击其中的任何一个之前初始化复选框的状态。 – Alex

+0

你得到一个空指针,因为你试图获取组上的复选框,而不是子组件。我认为最好通过重写'getChildView'函数来初始化自定义适配器中的复选框。 –

+0

谢谢。我一直在思考这些问题。不过,这改变了我的问题。我需要传递一个字符串才能执行填充我的数组列表的查询。我不知道如何将数据传递到适配器。 – Alex