Torsten Grote
Torsten Grote

Reputation: 321

Android RecyclerView Saving State Information

I have a RecyclerView whose adapter holds a SortedList of objects I can not modify.

My cards inside the RecyclerView should expand/collapse on click showing additional information when expanded. The problem is that there seems to be no way to store the information whether a card is expanded or collapsed since the ViewHolder gets recycled.

To make things more difficult, new items are added at the beginning and at the end of my adapter, so the positions change all the time. Even though new cards should be shown collapsed, they are sometimes shown as expanded when a ViewHolder of an expanded card gets recycled for the new card. This is when I tried to save the expand/collapse information in the ViewHolder directly.

Upvotes: 0

Views: 1886

Answers (1)

Torsten Grote
Torsten Grote

Reputation: 321

The correct solution seems to be using a wrapper object with two properties: the original (unmodifiable) object, and a boolean indicating whether the item is expanded or collapsed.

Then in the onBindViewHolder() method of the RecyclerView's adapter, you have to set your views to expanded or collapsed depending on the state of the wrapper object.

@Override
public void onBindViewHolder(final ViewHolder ui, int position) {
    if(wrapper_objects.get(position).expanded) {
        expandView(ui);
    } else {
        collapseView(ui);
    }

    // expand/collapse on click
    ui.expand.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if(wrapper_objects.get(position).expanded) {
                collapseView(ui);
                wrapper_objects.get(position).expanded = false;
            } else {
                expandView(ui);
                wrapper_objects.get(position).expanded = true;
            }
        }
    });
}

An additional problem, but rare problem might be that an API sometimes returns the same objects that were already in the SortedList. In this case, they then overwrite the expand/collapse state in the wrapper object. A hackish solution I found for this is doing this:

private SortedList<WrapperObject> wrapper_objects = new SortedList<>(WrapperObject.class, new SortedList.Callback<WrapperObject>(){
    @Override
     public boolean areContentsTheSame(WrapperObject old, WrapperObject new) {
        // keep state in new wrapper object
        new.expanded = old.expanded;

        return old.object.equals(new.object);
    }
}

Upvotes: 1

Related Questions