How to save scroll position of RecyclerView in Android?

Beginning from version 1.2.0-alpha02 of androidx recyclerView library, it is now automatically managed. Just add it with:

implementation "androidx.recyclerview:recyclerview:1.2.0-alpha02"

And use:

adapter.stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY

The StateRestorationPolicy enum has 3 options:

  • ALLOW — the default state, that restores the RecyclerView state immediately, in the next layout pass
  • PREVENT_WHEN_EMPTY — restores the RecyclerView state only when the adapter is not empty (adapter.getItemCount() > 0). If your data is loaded async, the RecyclerView waits until data is loaded and only then the state is restored. If you have default items, like headers or load progress indicators as part of your Adapter, then you should use the PREVENT option, unless the default items are added using MergeAdapter. MergeAdapter waits for all of its adapters to be ready and only then it restores the state.
  • PREVENT — all state restoration is deferred until you set ALLOW or PREVENT_WHEN_EMPTY.

Note that at the time of this answer, recyclerView library is still in alpha03, but alpha phase is not suitable for production purposes.


Save the current state of recycle view position @onPause:

    positionIndex= llManager.findFirstVisibleItemPosition();
    View startView = rv.getChildAt(0);
    topView = (startView == null) ? 0 : (startView.getTop() - rv.getPaddingTop());

Restore the scroll position @onResume:

    if (positionIndex!= -1) {
        llManager.scrollToPositionWithOffset(positionIndex, topView);
    }

or another way can be @onPause:

long currentVisiblePosition = 0;
currentVisiblePosition = ((LinearLayoutManager)rv.getLayoutManager()).findFirstCompletelyVisibleItemPosition();

restore @onResume:

((LinearLayoutManager) rv.getLayoutManager()).scrollToPosition(currentVisiblePosition);
currentVisiblePosition = 0;

A lot of these answers seem to be over complicating it.

The LayoutManager supports onRestoreInstanceState out of the box so there is no need to save scroll positions etc. The built in method already saves pixel perfect positions.

example fragment code (null checking etc removed for clarity):

private Parcelable listState;
private RecyclerView list;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    listState=savedInstanceState.getParcelable("ListState");

}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    outState.putParcelable("ListState", list.getLayoutManager().onSaveInstanceState());

}

then just call

list.getLayoutManager().onRestoreInstanceState(listState);

once your data has been reattached to your RecyclerView