How to save RecyclerView's scroll position using RecyclerView.State?

save recyclerview scroll position in fragment
recyclerview save item state
save recyclerview state android
recyclerview state scroll
stateful recyclerview
refreshing data in recyclerview and keeping its scroll position
how to retain the scroll position of a recyclerview on back press from another activity
parcelable recyclerviewstate

I have a question about Android's RecyclerView.State.

I am using a RecyclerView, how could I use and bind it with RecyclerView.State?

My purpose is to save the RecyclerView's scroll position.

How do you plan to save last saved position with RecyclerView.State?

You can always rely on ol' good save state. Extend RecyclerView and override onSaveInstanceState() and onRestoreInstanceState():

    @Override
    protected Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        LayoutManager layoutManager = getLayoutManager();
        if(layoutManager != null && layoutManager instanceof LinearLayoutManager){
            mScrollPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
        }
        SavedState newState = new SavedState(superState);
        newState.mScrollPosition = mScrollPosition;
        return newState;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        super.onRestoreInstanceState(state);
        if(state != null && state instanceof SavedState){
            mScrollPosition = ((SavedState) state).mScrollPosition;
            LayoutManager layoutManager = getLayoutManager();
            if(layoutManager != null){
              int count = layoutManager.getItemCount();
              if(mScrollPosition != RecyclerView.NO_POSITION && mScrollPosition < count){
                  layoutManager.scrollToPosition(mScrollPosition);
              }
            }
        }
    }

    static class SavedState extends android.view.View.BaseSavedState {
        public int mScrollPosition;
        SavedState(Parcel in) {
            super(in);
            mScrollPosition = in.readInt();
        }
        SavedState(Parcelable superState) {
            super(superState);
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            super.writeToParcel(dest, flags);
            dest.writeInt(mScrollPosition);
        }
        public static final Parcelable.Creator<SavedState> CREATOR
                = new Parcelable.Creator<SavedState>() {
            @Override
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            @Override
            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }

How to save RecyclerView's scroll position using , How do you plan to save last saved position with RecyclerView.State ? You can always rely on ol' good save state. Extend RecyclerView and override  Saving and restoring a RecyclerView’s position in Android Prerequisities. Next, make sure your controller class (Fragment, Activity, etc) implements ListPositioner (e.g. Saving the RecyclerView’s scroll position. To save the position, we’re just going to save the first fully visible item’s

If you are using LinearLayoutManager, it comes with pre-built save api linearLayoutManagerInstance.onSaveInstanceState() and restore api linearLayoutManagerInstance.onRestoreInstanceState(...)

With that, you can save the returned parcelable to your outState. e.g.,

outState.putParcelable("KeyForLayoutManagerState", linearLayoutManagerInstance.onSaveInstanceState());

, and restore restore position with the state you saved. e.g,

Parcelable state = savedInstanceState.getParcelable("KeyForLayoutManagerState");
linearLayoutManagerInstance.onRestoreInstanceState(state);

To wrap all up, your final code will look something like

private static final String BUNDLE_RECYCLER_LAYOUT = "classname.recycler.layout";

/**
 * This is a method for Fragment. 
 * You can do the same in onCreate or onRestoreInstanceState
 */
@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
    super.onViewStateRestored(savedInstanceState);

    if(savedInstanceState != null)
    {
        Parcelable savedRecyclerLayoutState = savedInstanceState.getParcelable(BUNDLE_RECYCLER_LAYOUT);
        recyclerView.getLayoutManager().onRestoreInstanceState(savedRecyclerLayoutState);
    }
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putParcelable(BUNDLE_RECYCLER_LAYOUT, recyclerView.getLayoutManager().onSaveInstanceState());
}

Edit: You can also use the same apis with the GridLayoutManager, as it is a subclass of LinearLayoutManager. Thanks @wegsehen for the suggestion.

Edit: Remember, if you are also loading data in a background thread, you will need to a call to onRestoreInstanceState within your onPostExecute/onLoadFinished method for the position to be restored upon orientation change, e.g.

@Override
protected void onPostExecute(ArrayList<Movie> movies) {
    mLoadingIndicator.setVisibility(View.INVISIBLE);
    if (movies != null) {
        showMoviePosterDataView();
        mDataAdapter.setMovies(movies);
      mRecyclerView.getLayoutManager().onRestoreInstanceState(mSavedRecyclerLayoutState);
        } else {
            showErrorMessage();
        }
    }

saved instance state and recyclerview scroll position, Save the recyclerview state: parce = recyclerview.onSaveInstanceState();. set the recyclerview state recyclerview.onRestoreState(parce);. i have 3 fragments using bottom navigation, each fragments fetch data from JSON, but when i go to another fragment and back to the previous fragment the data is gone and the fragment will fetch dat

Store

lastFirstVisiblePosition = ((LinearLayoutManager)rv.getLayoutManager()).findFirstCompletelyVisibleItemPosition();

Restore

((LinearLayoutManager) rv.getLayoutManager()).scrollToPosition(lastFirstVisiblePosition);

and if that doesn't work, try

((LinearLayoutManager) rv.getLayoutManager()).scrollToPositionWithOffset(lastFirstVisiblePosition,0)

Put store in onPause() and restore in onResume()

Retain & restore recycler view scroll position · GitHub, By default, if you scroll the parent RecyclerView, the nested RecyclerViews don't save and restore state automatically. You can observe this  Stack Overflow for Teams is a private, secure spot for you and your coworkers to find and share information. Learn more How to save scroll position of RecyclerView in Android?

I wanted to save Recycler View's scroll position when navigating away from my list activity and then clicking the back button to navigate back. Many of the solutions provided for this problem were either much more complicated than needed or didn't work for my configuration, so I thought I'd share my solution.

First save your instance state in onPause as many have shown. I think it's worth emphasizing here that this version of onSaveInstanceState is a method from the RecyclerView.LayoutManager class.

private LinearLayoutManager mLayoutManager;
Parcelable state;

        @Override
        public void onPause() {
            super.onPause();
            state = mLayoutManager.onSaveInstanceState();
        }

The key to getting this to work properly is to make sure you call onRestoreInstanceState after you attach your adapter, as some have indicated in other threads. However the actual method call is much simpler than many have indicated.

private void someMethod() {
    mVenueRecyclerView.setAdapter(mVenueAdapter);
    mLayoutManager.onRestoreInstanceState(state);
}

Saving scroll state of nested RecyclerViews, If you need to retain state information in those cases, it's best to save state To properly retain this state for RecyclerView , you can store the instance state  I have a recyclerView containing list of a objects of a class. Currently when I close my app all the list in the recyclerView gets lost and after restarting the app, recyclerView shows nothing(no list). What and How shall I use to retain the list even after my is closed and destroyed?

I Set variables in onCreate(), save scroll position in onPause() and set scroll position in onResume()

public static int index = -1;
public static int top = -1;
LinearLayoutManager mLayoutManager;

@Override
public void onCreate(Bundle savedInstanceState)
{
    //Set Variables
    super.onCreate(savedInstanceState);
    cRecyclerView = ( RecyclerView )findViewById(R.id.conv_recycler);
    mLayoutManager = new LinearLayoutManager(this);
    cRecyclerView.setHasFixedSize(true);
    cRecyclerView.setLayoutManager(mLayoutManager);

}

@Override
public void onPause()
{
    super.onPause();
    //read current recyclerview position
    index = mLayoutManager.findFirstVisibleItemPosition();
    View v = cRecyclerView.getChildAt(0);
    top = (v == null) ? 0 : (v.getTop() - cRecyclerView.getPaddingTop());
}

@Override
public void onResume()
{
    super.onResume();
    //set recyclerview position
    if(index != -1)
    {
        mLayoutManager.scrollToPositionWithOffset( index, top);
    }
}

Handling Configuration Changes, 0-alpha02 , RecyclerView offers a new API to let the Adapter block layout restoration until it is ready. Read on to learn how to use this new API  None of the code you posted should be necessary to save your RecyclerView's scroll position on orientation change. As long as the RecyclerView has a unique ID in your layout, it will save the scroll position for you automatically. Here is a very small sample app that shows automatic saving of scroll position, even with a dynamically added

Restore RecyclerView scroll position - Android Developers, With the default implementation, every time the RecyclerView's Adapter is assigned the position is reset. In this tutorial, I'll cover how to save,  RecyclerView state is saved and restored on rotation of phone; RecyclerView state is saved and restored on returning to activity with RecyclerView (which wasn't destroyed whilst the other activity was showing - which means that onRestoreInstanceState() isn't called !!) CODE

Saving and restoring a RecyclerView's position in Android, I want to find a way to save/restore the changes made to the listview at runtime A RecyclerView has equivalent capabilities through their LayoutManagers. 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.

Saving and restoring the state of a custom list adapter in a Fragment , I have a question about Android's RecyclerView.State. I am using a RecyclerView​, how could I use and bind it with RecyclerView.State? My purpose is to save  Create a List with RecyclerView Part of Android Jetpack. If your app needs to display a scrolling list of elements based on large data sets (or data that frequently changes), you should use RecyclerView as described on this page. Tip: Start with some template code in Android Studio by clicking File > New > Fragment > Fragment (List).

Comments
  • now I have another question, how , no , what is RecyclerView.State can do?
  • does this really work? I have tried this, but I keep getting a runtime exception like this: MyRecyclerView$SavedState cannot be cast to android.support.v7.widget.RecyclerView$SavedState
  • On the restore instance state we need to pass the superState to its super class (the recytcler view) like this: super.onRestoreInstanceState(((ScrollPositionSavingRecyclerView.SavedState) state).getSuperState());
  • This doesn't work if you extend the RecyclerView, you'll get BadParcelException.
  • None of this is necessary : if you use something like LinearLayoutManager / GridLayoutManager the "scroll position" is already saved automatically for you. (It's the mAnchorPosition in LinearLayoutManager.SavedState). If you're not seeing that, then something is wrong with how you are reapplying data.
  • This is clearly the best answer, why is this not accepted? Note that any LayoutManager has that, not only LinearLayoutManager, also GridLayoutManager, and if not its a false implementation.
  • linearLayoutManager.onInstanceState() always returns null --> check the source code. Unfortunately not working.
  • Doesn't RecyclerView do the state save of its LayoutManager in its own onSaveInstanceState? Looking at v24 of the support lib...
  • This works on a single RecyclerView but not if you have a ViewPager with a RecycerView on each page.
  • @Ivan, I think it works in a fragment (just checked), but not in onCreateView, but after data loading. See @Farmaker answer here.
  • This works, but you may need to reset the lastFirstVisiblePosition to 0 after restoring it. This case is useful when you have a fragment/activity that loads different data in one RecyclerView, for example, a file explorer app.
  • Excellent! It satisfies both coming back from a detail activity to the list, and saving state on screen rotation
  • what to do if my recyclerView is in SwipeRefreshLayout?