¿Cómo guardar la posición de desplazamiento de RecyclerView usando RecyclerView.State?

Tengo una pregunta sobre RecyclerView.State de Android.

Estoy usando RecyclerView, ¿cómo podría usarlo y vincularlo con RecyclerView.State?

Mi propósito es guardar la posición de desplazamiento de RecyclerView .

    ¿Cómo planea guardar la última posición guardada con RecyclerView.State ?

    Siempre puede confiar en el buen estado de guardado. Extienda RecyclerView y anule onSaveInstanceState () y 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.getChildCount(); 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 CREATOR = new Parcelable.Creator() { @Override public SavedState createFromParcel(Parcel in) { return new SavedState(in); } @Override public SavedState[] newArray(int size) { return new SavedState[size]; } }; } 

    Si está utilizando LinearLayoutManager, viene con un guardado predefinido api linearLayoutManagerInstance.onSaveInstanceState () y restaura api linearLayoutManagerInstance.onRestoreInstanceState (…)

    Con eso, puede guardar el paquete devuelto para su outState. p.ej,

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

    y restaurar la posición de restauración con el estado que guardó. p.ej,

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

    Para concluir, tu código final se verá algo así como

     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()); } 

    Editar: También puede usar las mismas API con GridLayoutManager, ya que es una subclase de LinearLayoutManager. Gracias @wegsehen por la sugerencia.

    Editar: Recuerde, si también está cargando datos en un hilo de fondo, necesitará una llamada a onRestoreInstanceState dentro de su método onPostExecute / onLoadFinished para la posición que se restaurará al cambiar la orientación, por ejemplo

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

    Almacenar

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

    Restaurar

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

    y si eso no funciona, prueba

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

    Poner tienda en onPause() y restaurar en onResume()

    Establezco las variables en onCreate (), guardo la posición de desplazamiento en onPause () y establezco la posición de desplazamiento en 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); } } 

    Quería guardar la posición de desplazamiento de Recycler View cuando me alejaba de la actividad de mi lista y luego hacer clic en el botón Atrás para navegar hacia atrás. Muchas de las soluciones proporcionadas para este problema fueron mucho más complicadas de lo necesario o no funcionaron para mi configuración, así que pensé en compartir mi solución.

    Primero guarda tu estado de instancia en onPause como muchos han mostrado. Creo que vale la pena enfatizar aquí que esta versión de onSaveInstanceState es un método de la clase RecyclerView.LayoutManager.

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

    La clave para que esto funcione correctamente es asegurarse de llamar a RestoreInstanceState después de conectar su adaptador, como algunos han indicado en otros hilos. Sin embargo, la llamada al método real es mucho más simple de lo que muchos han indicado.

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

    Ya no tiene que guardar y restaurar el estado usted mismo. Si configura una ID única en xml y recyclerView.setSaveEnabled (true) (verdadero de manera predeterminada), el sistema lo hará automáticamente. Aquí hay más sobre esto: http://trickyandroid.com/saving-android-view-state-correctly/

    Así es como restauro la posición de RecyclerView con GridLayoutManager después de la rotación cuando necesitas volver a cargar datos desde Internet con AsyncTaskLoader.

    Cree una variable global de Parcelable y GridLayoutManager y una cadena final estática:

     private Parcelable savedRecyclerLayoutState; private GridLayoutManager mGridLayoutManager; private static final String BUNDLE_RECYCLER_LAYOUT = "recycler_layout"; 

    Guarde el estado de gridLayoutManager en onSaveInstance ()

      @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable(BUNDLE_RECYCLER_LAYOUT, mGridLayoutManager.onSaveInstanceState()); } 

    Restaurar en onRestoreInstanceState

     @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); //restre recycler view at same position if (savedInstanceState != null) { savedRecyclerLayoutState = savedInstanceState.getParcelable(BUNDLE_RECYCLER_LAYOUT); } } 

    Luego, cuando el cargador recupera datos de Internet, usted restaura la posición de reciclaje de vista en onLoadFinished ()

     if(savedRecyclerLayoutState!=null){ mGridLayoutManager.onRestoreInstanceState(savedRecyclerLayoutState); } 

    … por supuesto, tienes que instanciar gridLayoutManager dentro deCreate. Aclamaciones

    Para mí, el problema fue que configuré un nuevo administrador de disposición cada vez que cambié mi adaptador, perdiendo la posición de desplazamiento de la cola en recyclerView.

    Aquí está mi enfoque para guardarlos y mantener el estado de la visión de reciclador en un fragmento. Primero, agregue los cambios de configuración en su actividad principal como se muestra a continuación.

     android:configChanges="orientation|screenSize" 

    Luego, en su Fragmento, declare el método de esta instancia

     private Bundle mBundleRecyclerViewState; private Parcelable mListState = null; private LinearLayoutManager mLinearLayoutManager; 

    Agregue el código siguiente en su método @onPause

     @Override public void onPause() { super.onPause(); //This used to store the state of recycler view mBundleRecyclerViewState = new Bundle(); mListState =mTrailersRecyclerView.getLayoutManager().onSaveInstanceState(); mBundleRecyclerViewState.putParcelable(getResources().getString(R.string.recycler_scroll_position_key), mListState); } 

    Agregue el método ChangeConfigartionChanged como a continuación.

     @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); //When orientation is changed then grid column count is also changed so get every time Log.e(TAG, "onConfigurationChanged: " ); if (mBundleRecyclerViewState != null) { new Handler().postDelayed(new Runnable() { @Override public void run() { mListState = mBundleRecyclerViewState.getParcelable(getResources().getString(R.string.recycler_scroll_position_key)); mTrailersRecyclerView.getLayoutManager().onRestoreInstanceState(mListState); } }, 50); } mTrailersRecyclerView.setLayoutManager(mLinearLayoutManager); } 

    Este enfoque resolverá tu problema. si tiene un administrador de diseño diferente, simplemente reemplace el administrador de diseño superior.

    Activity.java:

     public RecyclerView.LayoutManager mLayoutManager; Parcelable state; mLayoutManager = new LinearLayoutManager(this); // Inside `onCreate()` lifecycle method, put the below code : if(state != null) { mLayoutManager.onRestoreInstanceState(state); } @Override protected void onResume() { super.onResume(); if (state != null) { mLayoutManager.onRestoreInstanceState(state); } } @Override protected void onPause() { super.onPause(); state = mLayoutManager.onSaveInstanceState(); } 

    Por qué estoy usando OnSaveInstanceState() en onPause() significa, mientras se llamaría a otra actividad en Pause. Guardará esa posición de desplazamiento y restaurará la posición cuando regresemos de otra actividad.