糟糕的ExpandableListView组视图回收

时间:2015-06-28 14:58:58

标签: java android listview expandablelistview baseadapter

当我尝试使用延迟加载的imageViews作为组视图创建可扩展的列表视图时,我遇到了一个不好的问题。结果表明,每次打开一个组时,所有的组视图都会重新绘制,但会给它们一个随机的convertView(而不是他们的),这会导致非常糟糕的闪烁,因为之前的imageViews被randomely传递给了错误的组。您可以通过以下示例来体验此问题,该示例包含一个非常简单的ExpandableListView,具有延迟的组绘制,可以很好地突出显示这种不需要的行为。是否有更好的实现保留了在组开口上绑定的item / convertView?

-respondsToSelector:

1 个答案:

答案 0 :(得分:0)

你需要两个视图持有者一个用于父级,另一个用于子元素。

你可以尝试这样的事情。 public class MyExpandableListAdapter扩展了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);
    }
};

}