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í:
-
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;
-
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); }
-
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); } }
-
En el método
onSaveInstanceState
:@Override public void onSaveInstanceState(Bundle outState) { // Save RecyclerView state outState.putInt(RECYCLER_POSITION_KEY, mLayoutManager.findFirstCompletelyVisibleItemPosition()); super.onSaveInstanceState(outState); }
-
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:
- El estado de RecyclerView se guarda y restaura en la rotación del teléfono
-
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
}
}