2013-06-04 60 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