Search code examples
androidexpandablerecycle

Android ListView recycled - expandable item


I've created an expandable item for a ListView and the view is recycled correctly. The problem is when I expand one of these items, some hidden items are also expanded, which is clearly what I don't want.

For example, if I expand the item in 2nd position in the list, the 8th is also expanded. And vice-versa. This looks to be a recycled view which is not correctly collapsed.

Here are some quick screen of expand/collapse items.

enter image description here

enter image description here

Here is the code I use to create these items:

LayoutInflater inflater = (LayoutInflater) fragment.getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    final MessageHolder holder;
    if (convertView == null)
    {
        convertView = inflater.inflate(R.layout.test_message, parent, false);
        holder = new MessageHolder();

        // Retrieve layout elements
        holder.card = new WeakReference<ExpandableCardLayout>((ExpandableCardLayout) convertView.findViewById(R.id.card));
        holder.layout_comments = new WeakReference<LinearLayout>((LinearLayout) convertView.findViewById(R.id.layout_comments));
        holder.layout_loading = new WeakReference<LinearLayout>((LinearLayout) convertView.findViewById(R.id.layout_loading));
        holder.spinner_loading = new WeakReference<FlatLoadingSpinner>((FlatLoadingSpinner) convertView.findViewById(R.id.spinner_loading));

        // Attach holder
        convertView.setTag(holder);
    }
    else
    {
        holder = (MessageHolder) convertView.getTag();
    }

    // Attach listener
    holder.card.get().setOnExpandListener(new OnExpandListener() {
        @Override
        public void onExpand()
        {
            handler.postDelayed(new Runnable() {
                @Override
                public void run()
                {
                    // Hide loading
                    holder.layout_loading.get().setVisibility(View.GONE);

                    // Add comments
                    List<View> comments = buildComments(null);
                    for (int i=0; i<comments.size(); i++) holder.layout_comments.get().addView( comments.get(i) );
                }
            }, 1000);
        }

        @Override
        public void onCollapse()
        {               
            // Remove everything
            while (holder.layout_comments.get().getChildCount() > 0) holder.layout_comments.get().removeViewAt(0);

            // Show loading
            holder.layout_loading.get().setVisibility(View.VISIBLE);
        }
    });

    return convertView;

My question is: How to avoid the collapse view to be expanded on recycled elements ?


Solution

  • You have to manually remove views added in onExpand(). ListView does not know anything about your expanding logic and caches and reuses list item views 'as is'.

    Alternatively you should consider using ExpandableListView as this component is designed exactly for situations like yours.

    PS. I do not understand why you are using WeakReferences in hour holder object.