Retain & restore recycler view scroll position

  1 mins read

If you come to a situation where you need to retain the scroll position of a recycler view (i.e. configuration change, going back on a certain flow), you might think that you have a retain and restore the scroll manually. Yes, in fact, you have to, but LayoutManager has a convenient API that makes things a bit easier.

LayoutManager.onSaveInstanceState()
LayoutManager.onRestoreInstanceState(Parcelable state);

These two methods are the ones that you need to use in order to retain and restore the scroll position later on. Now comes the tricky part, In order to work the content of the recycler view has to be loaded before restoring the scroll position.

That means that if you are loading the data asynchronously on your recycler view you will have to keep a reference of the saved stated

First save the current state.

@Override
protected Parcelable onSaveInstanceState() {
   Bundle bundle = new Bundle();
   bundle.putParcelable(SAVED_LAYOUT_MANAGER, recyclerView.getLayoutManager().onSaveInstanceState());
   return bundle;
}

Then keep a reference from the state previously saved

@Override
protected void onRestoreInstanceState(Parcelable state) {
    if (state instanceof Bundle) {
        layoutManagerSavedState = ((Bundle) state).getParcelable(SAVED_LAYOUT_MANAGER);
    }
    super.onRestoreInstanceState(state);
}

And restore it after  you’ve populated the adapter with data.


public void setItems(List objects) {
    adapter.setItems(objects);
    restoreLayoutManagerPosition();
}
private void restoreLayoutManagerPosition() {
    if (layoutManagerSavedState != null) {
        recyclerView.getLayoutManager().onRestoreInstanceState(layoutManagerSavedState);
    }
}

Voila!

Personal thoughts

IMO the LayoutManager should keep the restored instance state and apply it once the dataset gets loaded, this would definitely make the code much cleaner and stylish. Instead, what it does under the hood is discard the pendingScrollPosition if the attached recyclerView does not have items when onRestoreInstanceState method is called on the layout manager.

Written by:

Carlos Morera de la Chica

  • Hey, I really appreciate your blog post. It saved me a lot of time and helped to remove a problem that I previously had to work around, so thank you very much 🙂

    • Carlos Morera de la Chica

      My pleasure 🙂

  • Lenny K

    hi carlos, i’ve tried to put onSaveInstanceState and onRestoreInstanceState on activity but it’s not working, and i try to put on adapter it also not working, sorry i’m a newbie on android, i didn’t understand about this. I’m using ObservableRecyclerView, could you explain with sample? thanks

  • This worked perfectly, even though our use case was a little different. Our app maintains a lists of fragments in a custom backstack, and on restore we wanted to also properly restore the scroll position. We were able to use your method to accomplish this.

    Best of all, we get the pixel-perfect position restored even after rotation.

  • Saik

    Cheers, I feel really stupid, I wasn’t using this, and simply keeping the data and reloading the recycler. I actually also wasn’t using onRestoreSavedInstanceState, I just had functions to handle a non-null SavedInstanceState in onCreate()s… for like a year 😛

  • noob08

    hi thanks for this it solve one of my problem. now how to also set the selected item position on restore or resume of a fragment?

  • Ifeoma Okereke

    This was helpful. Thanks for sharing.