savedinstancestate practices example best activity android listview android-recyclerview

practices - onsaveinstancestate android fragment



RecyclerView almacenar/restaurar estado entre actividades (7)

Estoy migrando mis ListViews a RecyclerViews. Con las vistas de lista, utilicé la técnica común descrita here para almacenar y restaurar la posición de desplazamiento entre actividades.

¿Cómo hacer lo mismo con RecyclerViews? RecyclerView.onSaveInstanceState() parece tener acceso protected , por lo que no se puede usar directamente.


Cuando use recyclerView.getLayoutManager().onSaveInstanceState() no olvide verificar nulo :

@Override public void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); if (recyclerView != null) { outState.putParcelable(SCROLL_POSITION, recyclerView.getLayoutManager().onSaveInstanceState()); } }


Esa es mi solución, restaura los artículos y la posición de RecyclerView

1) guardar el estado de vista del reciclador en el método onSaveInstanceState

@Override protected void onSaveInstanceState(Bundle outState) { Parcelable listState = myRecyclerView.getLayoutManager().onSaveInstanceState(); // putting recyclerview position outState.putParcelable(SAVED_RECYCLER_VIEW_STATUS_ID, listState); // putting recyclerview items outState.putParcelableArrayList(SAVED_RECYCLER_VIEW_DATASET_ID,mDataset); super.onSaveInstanceState(outState); }

2) Verifique el paquete saveInstanceState en el método onCreate

@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState==null){ getRemoteData(); // No saved data, get data from remote }else{ restorePreviousState(); // Restore data found in the Bundle } }

3) Restaurar los datos de la vista del reciclador si la pantalla se ha girado

public void restorePreviousState(){ // getting recyclerview position mListState = mSavedInstanceState.getParcelable(SAVED_RECYCLER_VIEW_STATUS_ID); // getting recyclerview items mDataset = mSavedInstanceState.getParcelableArrayList(SAVED_RECYCLER_VIEW_DATASET_ID); // Restoring adapter items mAdapter.setItems(mDataset); // Restoring recycler view position mRvMedia.getLayoutManager().onRestoreInstanceState(mListState); }


Ok, entonces para responder mi propia pregunta. Según tengo entendido, dado que han desacoplado el código de diseño y el código de reciclaje de la vista (de ahí el nombre), el componente responsable de mantener el estado de diseño (y restaurarlo) ahora es el LayoutManager utilizado en su vista de reciclador.

Por lo tanto, para almacenar el estado usa el mismo patrón, pero en el administrador de diseño y no en la vista de reciclador:

protected void onSaveInstanceState(Bundle state) { super.onSaveInstanceState(state); // Save list state mListState = mLayoutManager.onSaveInstanceState(); state.putParcelable(LIST_STATE_KEY, mListState); }

Restaurar estado en onRestoreInstanceState() :

protected void onRestoreInstanceState(Bundle state) { super.onRestoreInstanceState(state); // Retrieve list state and list/item positions if(state != null) mListState = state.getParcelable(LIST_STATE_KEY); }

Luego actualice el LayoutManager (lo hago en onResume() ):

@Override protected void onResume() { super.onResume(); if (mListState != null) { mLayoutManager.onRestoreInstanceState(mListState); } }


Teniendo en cuenta que definió un RecyclerView ( mRecyclerView ) y un LayoutManager ( mLayoutManager ) en su código y todo funciona bien hasta ahora, la solución para guardar la posición ( mPosition ) de su RecyclerView se ve así:

  1. Variables y constantes utilizadas:

    private final String RECYCLER_POSITION_KEY = "recycler_position"; private int mPosition = RecyclerView.NO_POSITION; private RecyclerView mRecyclerView; private LinearLayoutManager mLayoutManager; private static Bundle mBundleState;

  2. En el método onPause :

    @Override protected void onPause() { super.onPause(); // Save RecyclerView state mBundleState = new Bundle(); mPosition = mLayoutManager.findFirstCompletelyVisibleItemPosition(); mBundleState.putInt(RECYCLER_POSITION_KEY, mPosition); }

  3. En el método onResume :

    @Override protected void onResume() { super.onResume(); // Restore RecyclerView state if (mBundleState != null) { mPosition = mBundleState.getInt(RECYCLER_POSITION_KEY); if (mPosition == RecyclerView.NO_POSITION) mPosition = 0; // Scroll the RecyclerView to mPosition mRecyclerView.smoothScrollToPosition(mPosition); } }

  4. En el método onSaveInstanceState :

    @Override public void onSaveInstanceState(Bundle outState) { // Save RecyclerView state outState.putInt(RECYCLER_POSITION_KEY, mLayoutManager.findFirstCompletelyVisibleItemPosition()); super.onSaveInstanceState(outState); }

  5. En el método onRestoreInstanceState :

    @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { // Restore RecyclerView state if (savedInstanceState.containsKey(RECYCLER_POSITION_KEY)) { mPosition = savedInstanceState.getInt(RECYCLER_POSITION_KEY); if (mPosition == RecyclerView.NO_POSITION) mPosition = 0; // Scroll the RecyclerView to mPosition mRecyclerView.smoothScrollToPosition(mPosition); } super.onRestoreInstanceState(savedInstanceState); }


Use este código en onPause() y onResume() para guardar y restaurar la posición de desplazamiento.

private Parcelable recyclerViewState; recyclerViewState = mrecyclerView.getLayoutManager().onSaveInstanceState();//save mrecyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);//restore


Encontré una solución mejor : esta solución tiene los siguientes beneficios:

  1. El estado de RecyclerView se guarda y restaura en la rotación del teléfono
  2. El estado RecyclerView se guarda y restaura al volver a la actividad con RecyclerView (que no se destruyó mientras se mostraba la otra actividad, lo que significa que no se llama a onRestoreInstanceState() !!)

CÓDIGO

public class ActivityItemList extends AppCompatActivity { private final String KEY_RECYCLER_STATE = "recycler_state"; private RecyclerView mRecyclerView; private static Bundle mBundleRecyclerViewState; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_list);//set to whatever layout name you have mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);//set to whatever view id you use // don''t forget to set your adapter } @Override protected void onPause() { super.onPause(); // save RecyclerView state mBundleRecyclerViewState = new Bundle(); Parcelable listState = mRecyclerView.getLayoutManager().onSaveInstanceState(); mBundleRecyclerViewState.putParcelable(KEY_RECYCLER_STATE, listState); } @Override protected void onResume() { super.onResume(); // restore RecyclerView state if (mBundleRecyclerViewState != null) { Parcelable listState = mBundleRecyclerViewState.getParcelable(KEY_RECYCLER_STATE); mRecyclerView.getLayoutManager().onRestoreInstanceState(listState); } } }


public class MainActivity extends AppCompatActivity { Parcelable recyclerViewState; ....... @Override protected void onPause() { super.onPause(); recyclerViewState = MainAnecdotesView.getLayoutManager().onSaveInstanceState();//save } @Override protected void onResume() { super.onResume(); if(recyclerViewState!=null) MainAnecdotesView.getLayoutManager().onRestoreInstanceState(recyclerViewState);//restore } }