Search code examples
javaandroidandroid-activityactivity-lifecycle

When App is Pushed to the Background and Recreated, RecyclerView Not Restoring LayoutManager State


I initially followed the accepted answer in this previously posted question about how to save and restore the layout manager for a RecyclerView.

I have my RecyclerView in Activity B. [Note: Activity A will launch Activity B, transferring data via an intent.]

When a user clicks a viewholder in Activity B, Activity C is launched. Once Activity C is closed and destroyed, Activity B is visible, and I can see all of my data restored in the RecyclerView.

The Problem: However, if I navigate away from my app (ie pressing the Home Key), it is pushed to the background. When my app is reinstated, onCreate() is called again. The LayoutManager's state is being saved, however none of my data is showing in the RecyclerView.

I can tell my LayoutManager state was saved after some debugging. It shows up as this when onCreate() is called again after reinstating the app from the background:

Saved Instance State = Bundle[{ActivityB - Linear Layout State=android.support.v7.widget.LinearLayoutManager$SavedState@6358f8f, android:viewHierarchyState=Bundle[mParcelledData.dataSize=1296]}]

I am not sure how to fix this after hours of trying.

My Code:

public class ActivityB extends AppCompatActivity {

      private RecyclerView recyclerView;
      private LinearLayoutManager linearLayoutManager;
      private Parcelable linearLayoutState;
      private RecyclerAdapter adapter;
      private Button more;
      private String id;
      private List<VideoItem> list;
      private List<VideoItem> newList;
      private final String LINEARLAYOUT_STATE_KEY = "Activity B - Linear Layout State";

      @Override
      protected void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
             setContentView(R.layout.activity_blayout);

             // Retrieving data from Activity A
             Intent intent = getIntent();
             Bundle bundle = intent.getBundleExtra("bundle");
             someClass.innerClass class = bundle.getParcelable("data");
             id = class.getID();
             list = class.getList();
             newList = new ArrayList<>();

             // Instantiating Recycler View
             recyclerView = (RecyclerView)findViewById(R.id.activityb_recyclerview);
             recyclerView.setNestedScrollingEnabled(false);

             linearLayoutManager = new LinearLayoutManager(context);
             recyclerView.setLayoutManager(linearLayoutManager);

             adapter = new RecyclerAdapter();
             recyclerView.setAdapter(adapter);

             moreButton = (Button)findViewById(R.id.activityb_more);
             moreButton.setOnClickListener(new fetchMoreClickListener());
        }

        @Override
        public void onResume(){
              if (linearLayoutState != null) {
                 linearLayoutManager.onRestoreInstanceState(linearLayoutState);
              } else {
                 // If no layout state is found, I need to populate my
                 // adapter.
                 // Here I am simply cloning my list again, to keep the original
                 // list intact. generateSubset() removes items from the cloned list 
                 // to create a smaller subset that is added to the adapter.
                 for (ListItem item : list){
                        newList.add(new ListItemi(item));
                 }
                 adapter.addItems(generateSubset(0));
              }
              super.onResume();
        }

        @Override
        protected void onSaveInstanceState(Bundle outState) {
               linearLayoutState = linearLayoutManager.onSaveInstanceState();
               outState.putParcelable(LINEARLAYOUT_STATE_KEY, linearLayoutState);
               super.onSaveInstanceState(outState);
        }

        @Override
        protected void onRestoreInstanceState(Bundle savedInstanceState) {
               super.onRestoreInstanceState(savedInstanceState);
               linearLayoutState = savedInstanceState.getParcelable(LINEARLAYOUT_STATE_KEY);
        }

The other Activity LifeCycle Methods have not been overridden. I am not getting any error messages. Just my data stored in my viewholders is no longer showing in the RecyclerView.

Edit 1:

Here is my RecyclerAdapter code:

public class RecyclerAdapter extends RecyclerView.Adapter{ private static Date now; private List list;

public static class ItemHolder extends RecyclerView.ViewHolder
        implements View.OnClickListener {

    private Context context;
    private String key;
    private Bundle itemBundle;
    private SimpleDraweeView photo;
    private TextView title;

    public ItemHolder(Context context, View view){
        super(view);

        this.context = context;
        this.key = null;
        this.itemBundle = null;
        photo = (SimpleDraweeView)view.findViewById(R.id.itemholder_photo);
        title = (TextView)view.findViewById(R.id.itemholder_title);
        view.setOnClickListener(this);
    }

    public void bindData(Item item){
        if (key == null){ key = item.getID(); }
        if (itemBundle == null){
            itemBundle = new Bundle();
            itemBundle.setClassLoader(Item.class.getClassLoader());
            itemBundle.putParcelable("data", item);
        }

        photo.setImageURI(Uri.parse(item.getPhotoURL()));
    }

    @Override
    public void onClick(View view) {
        Intent intent = new Intent(context, ActivityB.class);
        intent.putExtra("bundle", itemBundle);
        context.startActivity(intent);
    }
}

public RecyclerAdapter(){
    this.list = new ArrayList<>();
    this.now = new Date();
}

public RecyclerAdapter(ArrayList<VideoItem> list){
    this.list = list;
    this.now = new Date();
    this.notifyItemRangeInserted(0, list.size());
}

@Override
public RecyclerAdapter.ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    Context context = parent.getContext();
    View recyclerItem = LayoutInflater.from(context)
            .inflate(R.layout.itemholder_item, parent, false);

    return new ItemHolder(context, recyclerItem);
}

@Override
public void onBindViewHolder(RecyclerAdapter.ItemHolder holder, int position) {
    Item item = list.get(position);
    holder.bindData(item);
}

private static Date getNow(){ return now; }

private static void updateNow(){ now = new Date(); }

@Override
public int getItemCount() {
    return list.size();
}

public void addItem(Item item){
    list.add(item);
    this.notifyItemInserted(list.size() - 1);
}

public void addItems(ArrayList<Item> items){
    int oldSize = list.size();
    list.addAll(items);
    this.notifyItemRangeInserted(oldSize, items.size());
}

}


Solution

  • Try changing your onResume() method to look something like the following:

    @Override
        public void onResume(){
              super.onResume(); 
              if (linearLayoutState != null) {
                 linearLayoutManager.onRestoreInstanceState(linearLayoutState);
              } 
                 // Here comes the code to populate your data. 
                 // I'm not sure how you do this, so I just copy/paste your code
                 for (ListItem item : list){
                        newList.add(new ListItemi(item));
                 }
                 // Now instatiate and add the adapter to the RecyclerView
                 adapter = new RecyclerAdapter(newList);
                 recyclerView.setAdapter(adapter);
              }
        }