Do I need multiple viewHolders for ExpandableListView?

我怕爱的太早我们不能终老 提交于 2019-12-03 21:33:14

You have one ViewHolder reference in your Adapter for all your Views. This makes no sense because every View in the List has its own instance of the ViewHolder which you get by View.getTag().

You could set an int[] with the positions you need as a Tag of CheckBox

    int[] positions = new int[2];
    positions[0] = childPosition;
    positions[1] = groupPosition;
    mViewHolder.mCheckBox.setTag(positions);

and in onClick()

    CheckBox box = (CheckBox) v;
    int[] posTag = (int[]) v.getTag();

Then you have the CheckBox for the state and the positions for the rest

I accepted Towlie288's answer because it pointed me in the right direction. Here's the code change that made everything work:

public class MyExpandableListAdapter extends BaseExpandableListAdapter {

    private Context mContext;
    private ArrayList<ContactNameItems> mListDataHeader;
    private ArrayList<String> selectedNumbers;

    private HashMap<String, List<ContactPhoneItems>> mListDataChild;

    private ChildViewHolder childViewHolder;
    private GroupViewHolder groupViewHolder;

    public MyExpandableListAdapter(Context context,
            ArrayList<ContactNameItems> listDataHeader,
            HashMap<String, List<ContactPhoneItems>> listDataChild,
            ArrayList<String> listOfNumbers) {

        mContext = context;
        mListDataHeader = listDataHeader;
        mListDataChild = listDataChild;
        selectedNumbers = listOfNumbers;

    }

    @Override
    public int getGroupCount() {
        return mListDataHeader.size();
    }

    @Override
    public ContactNameItems getGroup(int groupPosition) {
        return mListDataHeader.get(groupPosition);
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded,
            View convertView, ViewGroup parent) {

        String contactName = getGroup(groupPosition).getName();
        Bitmap contactImage = getGroup(groupPosition).getImage();

        if (convertView == null) {

            LayoutInflater inflater = (LayoutInflater) mContext
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.contact_name_item, null);

            groupViewHolder = new GroupViewHolder();

            groupViewHolder.mContactName = (TextView) convertView
                    .findViewById(R.id.lblListHeader);

            groupViewHolder.mContactImage = (ImageView) convertView
                    .findViewById(R.id.ivContactPhoto);

            convertView.setTag(groupViewHolder);
        } else {

            groupViewHolder = (GroupViewHolder) convertView.getTag();
        }

        if (contactImage != null) {
            groupViewHolder.mContactImage.setImageBitmap(contactImage);

        } else {
            groupViewHolder.mContactImage
                    .setImageResource(R.drawable.default_contact);
        }

        groupViewHolder.mContactName.setText(contactName);

        return convertView;
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return mListDataChild.get(mListDataHeader.get(groupPosition).getName())
                .size();
    }

    @Override
    public ContactPhoneItems getChild(int groupPosition, int childPosition) {
        return mListDataChild.get(mListDataHeader.get(groupPosition).getName())
                .get(childPosition);
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    @Override
    public View getChildView(int groupPosition, final int childPosition,
            boolean isLastChild, View convertView, ViewGroup parent) {

        String numberText = getChild(groupPosition, childPosition).getNumber();
        String typeText = getChild(groupPosition, childPosition).getPhoneType();

        final int mGroupPosition = groupPosition;

        if (convertView == null) {

            LayoutInflater inflater = (LayoutInflater) this.mContext
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.contact_detail_item, null);

            childViewHolder = new ChildViewHolder();

            childViewHolder.mPhoneNumber = (TextView) convertView
                    .findViewById(R.id.tv_phone_number);

            childViewHolder.mPhoneType = (TextView) convertView
                    .findViewById(R.id.tv_phone_type);

            childViewHolder.mCheckBox = (CheckBox) convertView
                    .findViewById(R.id.checkBox);

            childViewHolder.mCheckBox.setOnCheckedChangeListener(checkListener);

            convertView.setTag(childViewHolder);

        } else {

            childViewHolder = (ChildViewHolder) convertView.getTag();
        }

        childViewHolder.mPhoneNumber.setText(numberText);
        childViewHolder.mPhoneType.setText(typeText);

        ContactPhoneItems cpi = getChild(mGroupPosition, childPosition);

        childViewHolder.mCheckBox.setTag(cpi);
        childViewHolder.mCheckBox.setChecked(cpi.getSelected());

        // for managing the state of the boolean
        // array according to the state of the
        // CheckBox

        childViewHolder.mCheckBox
                .setOnClickListener(new View.OnClickListener() {

                    String contactNumber = mListDataChild
                            .get(mListDataHeader.get(mGroupPosition).getName())
                            .get(childPosition).getNumber();

                    public void onClick(View v) {

                        boolean isChecked = ((CheckBox) v).isChecked();

                        if (isChecked) {

                            selectedNumbers.add(contactNumber);

                        } else {

                            selectedNumbers.remove(contactNumber);
                        }

                        getChild(mGroupPosition, childPosition).setSelected(isChecked);
                        notifyDataSetChanged();
                    }
                });

        return convertView;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return false;
    }

    @Override
    public boolean hasStableIds() {
        return false;
    }

    public ArrayList<String> getSelectedNumbers() {

        return selectedNumbers;
    }

    public final class GroupViewHolder {

        TextView mContactName;
        ImageView mContactImage;
    }

    public final class ChildViewHolder {

        TextView mPhoneNumber;
        TextView mPhoneType;
        CheckBox mCheckBox;
    }

    OnCheckedChangeListener checkListener = new OnCheckedChangeListener() {

        @Override
        public void onCheckedChanged(CompoundButton buttonView,
                boolean isChecked) {

            ContactPhoneItems c = (ContactPhoneItems) buttonView.getTag();
            c.setSelected(isChecked);
        }
    };
}

This happens if a Child's view is reusing a Group's view, also the ViewHolder of it. Obviously, it cannot find mCheckBox in line 165, because it has not been set.
Simply adding a flag in ViewHolder, to check whether it is a Child's ViewHolder could solve your problem. No need to have two kinds of ViewHolder here.
Hope is helps

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!