Estoy migrando mi ListViews a RecyclerViews. Con listviews he utilizado la técnica común descrito aquí para guardar y restaurar la posición de desplazamiento entre las actividades.

Cómo hacer lo mismo con RecyclerViews? el RecyclerView.onSaveInstanceState() parecen tener protected acceso, por lo que no puede ser utilizado directamente.

InformationsquelleAutor khusrav | 2015-01-30

7 Comentarios

  1. 83

    Ok, así que para responder a mi propia pregunta. Como yo lo entiendo, ya que ha desacoplado el diseño de código y la vista de reciclaje de código (de ahí el nombre), el componente responsable por la celebración de diseño de estado (y restauración) ahora es el LayoutManager utilizado en su recyclerview.

    Por lo tanto, para almacenar el estado utiliza el mismo patrón, pero en el gestor de diseño y no la recyclerview:

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

    Restaurar el estado en el 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);
    }

    A continuación, actualizar el LayoutManager (yo lo hago en onResume()):

    @Override
    protected void onResume() {
        super.onResume();
    
        if (mListState != null) {
            mLayoutManager.onRestoreInstanceState(mListState);
        }
    }
    • tienes razón, va a arreglarlo.
    • lo que si onRestoreInstanceState() nunca se llama ?
    • Hola, ¿el código de arriba me ayudan con un RecyclerView lista donde instancestate no se guarda entre las actividades? He publicado la siguiente pregunta aquí: stackoverflow.com/questions/35413495/…
    • la mejor manera de responder sería para ejecutarlo.
    • Pero, ¿qué acerca de adaptador?
    • Usted puede optimizar su onRestoreInstanceState() más por la eliminación de la verificación null. Como por Android documentación: «El sistema de llamadas de onRestoreInstanceState() sólo si hay un estado guardado para restaurar, por lo que no es necesario comprobar si el Paquete es nulo». No me molesto ni nada.
    • ¿no deberías estar llamando state.getParcelable con el parámetro LIST_STATE_KEY en lugar de "myState"?
    • sí. En realidad en mi código que ambos tenían este valor, por lo que no he prestado atención al responder. Pero, sería correcto uso mismas variables.
    • Si usted está usando un Fragment, en lugar de restaurar el estado de onRestoreInstanceState, puede hacerlo de forma segura en onActivityCreated.
    • Esto hace el truco a la perfección.
    • He recyclerView cuyo estado quiero poner en savedInstance estado, pero siempre que intento restaurar su estado me da un error que es nulo. Estoy siguiendo el mismo código de la suya.
    • Tengo un problema similar aquí: stackoverflow.com/questions/52176812/…. Agradecería cualquier ideas sobre cómo resolver.
    • para una tabla similar, tengo una columna especial llamada ‘posición’, que representa el orden en que los elementos deben ser demostrado. Cuando drag-n-drop, puedo cambiar los valores de la posición del elemento arrastrado y todos los demás afectados.
    • Ok entiendo. ¿Guardar las posiciones en una base de datos o un objeto ArrayList o SparseArray utilizando onSaveInstanceState() y, a continuación, onRestoreInstanceState()? Y, a continuación, recuperar la base de datos de posición o una Matriz en la onResume() o onCreate()?

  2. 20

    He encontrado una solución mejor – esta solución tiene las siguientes ventajas :

    1. RecyclerView estado guardado y restaurado en rotación de teléfono
    2. RecyclerView estado guardado y restaurado en volviendo a la actividad con RecyclerView (que no fue destruido, mientras que la otra actividad fue mostrar lo que significa que onRestoreInstanceState() no se llama !!)

    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);
            }
        }
    }
    • Hola, ¿el código de arriba me ayudan con un RecyclerView lista donde instancestate no se guarda entre las actividades? He publicado la siguiente pregunta aquí: stackoverflow.com/questions/35413495/…?
    • He añadido el código de arriba para mi RecyclerView actividad sin suerte. Cuando va a una actividad anterior y, a continuación, volver a la recién creada RecyclerView lista, la lista de nuevos elementos que se pierde y solo puedo ver la lista predeterminada de diseño.
    • ¿Por qué guardar el estado en onPause()? En este momento la actividad no es destruido. El estado está intacto. No hay nada que restaurar.
    • de la frustración porque he tenido momentos de OnSaveInstanceState() no :/
    • genial, muchas gracias por tu ayuda
    • Yo estaba haciendo un poco de investigación adicional y descubierto en Google de código de ejemplo que es probable que sea mucho mejor simplemente para guardar y restaurar la posición de desplazamiento en lugar de serializar el administrador del estado. Ver \sdk\samples\android-21\ui\views\RecyclerView\Application\src\main\java\com\example\android\recyclerview\RecyclerViewFragment.java
    • El uso de variables estáticas para guardar el estado durante los cambios de configuración es una blasfemia en el mundo Android. Definitivamente, usted debe utilizar el ciclo de vida de Android, que está diseñado precisamente para esta tarea.
    • Esto va a funcionar, pero usted no tiene que usar una referencia estática. Sólo puede almacenar en el paquete de onSaveInstanceState, y restaurarla en onCreate.
    • sí, yo lo hago igual que ahora. Sin embargo, cuando hice este post he observado OnSaveInstanceState() no se llama.
    • En algún lugar tengo un problema similar aquí: stackoverflow.com/questions/52176812/…. Agradecería cualquier ideas sobre cómo resolver.
    • Esta solución funciona con ViewModel. si necesitamos guardar el estado de la vista, que se encuentra en el Fragmento, necesitamos enlazar ViewModel en la actividad y guardar/restaurar los estados de las variables de ViewModel. Y no necesitamos ningún variables estáticas =)

  3. 10

    Utilizar 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
    • parece que algo falta aquí porque recyclerViewState nunca se guarda en cualquier lugar
    • Usted puede guardar cualquier forma que desee, dependiendo de cómo desea implementar.
  4. 7

    Esa es mi solución, se restaura ambos elementos y RecyclerView posición

    1) guardar reciclador de estado de vista 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) Compruebe Bundle savedInstanceState 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) Restauración de reciclado de los datos de la vista 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);
    }
    • Usted no debe guardar el conjunto de datos con savedInstanceState. developer.android.com/topic/libraries/architecture/…
    • Gracias por la sugerencia de @jakk, me voy a dar clase ViewModel una oportunidad!
    • ViewModel es una mala idea. Tenga cuidado si usted desea utilizar. techyourchance.com/…
    • Gracias por tu sugerencia de @Kalinga. Tuviste mala experiencia con ViewModel?
    • No. He decidido no usarlo, ya que añade más código hinchazón en lugar de ayudar a usted & dirección de no guardar/restaurar el flujo, que se han de abordar en anycase. Una vez que implementar guardar/restaurar, no hay ninguna ventaja real de la utilización de ViewModel
    • Asistí a la Udacity Android Nanodegree desarrollador del programa, durante el curso de la ViewModel no fue mencionado, a pesar de la «SavedInstanceState» método, así que supongo que la segunda es la cosa correcta de hacer en estos casos
    • Gallazzi En tu #2 arriba, lo que es mSavedInstanceState define como?
    • gracias por la pregunta, que fue un error. He editado la respuesta sustitución de mSavedInstanceState con savedInstanceState procedentes de método onCreate
    • Gallazzi Ok, entendido y gracias por la aclaración.

  5. 1
    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
        }
    }
  6. 0

    Cuando se utiliza recyclerView.getLayoutManager().onSaveInstanceState() no se olvide de comprobar null:

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

    Teniendo en cuenta que usted define un RecyclerView (mRecyclerView) y un LayoutManager (mLayoutManager) en el código y todo está funcionando bien hasta ahora, la solución en el ahorro de la posición (mPosition) de su RecyclerView se parece a esto:

    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 onPause método:

      @Override
      protected void onPause()
      {
          super.onPause();
      
          //Save RecyclerView state
          mBundleState = new Bundle();
          mPosition = mLayoutManager.findFirstCompletelyVisibleItemPosition();
          mBundleState.putInt(RECYCLER_POSITION_KEY, mPosition);
      }
    3. En onResume método:

      @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 onSaveInstanceState método:

      @Override
      public void onSaveInstanceState(Bundle outState) {
          //Save RecyclerView state
          outState.putInt(RECYCLER_POSITION_KEY,  mLayoutManager.findFirstCompletelyVisibleItemPosition());
      
          super.onSaveInstanceState(outState);
      }
    5. En onRestoreInstanceState método:

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

Dejar respuesta

Please enter your comment!
Please enter your name here