Tengo una pregunta sobre RecyclerView.State de Android .
Estoy usando un RecyclerView, ¿cómo podría usarlo y vincularlo con RecyclerView.State?
Mi propósito es guardar la posición de desplazamiento de RecyclerView .
Tengo una pregunta sobre RecyclerView.State de Android .
Estoy usando un 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 planeas 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.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];
}
};
}
Actualizar
A partir del
recyclerview:1.2.0-alpha02
lanzamientoStateRestorationPolicy
se ha introducido. Podría ser un mejor enfoque para el problema dado.Este tema se ha tratado en el artículo medio de desarrolladores de Android .
Además, @ rubén-viguera compartió más detalles en la respuesta a continuación. https://stackoverflow.com/a/61609823/892500
Respuesta antigua
Si está utilizando LinearLayoutManager, viene con la api linearLayoutManagerInstance.onSaveInstanceState () preconstruida y la restauración api linearLayoutManagerInstance.onRestoreInstanceState (...)
Con eso, puede guardar el parcelable devuelto en su outState. p.ej,
y restaure la posición de restauración con el estado que guardó. p.ej,
Para resumir todo, su código final se verá algo así como
Editar: también puede usar las mismas apis 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 en segundo plano, deberá llamar a onRestoreInstanceState dentro de su método onPostExecute / onLoadFinished para que la posición se restaure al cambiar de orientación, por ejemplo
fuente
RecyclerView
pero no si tiene unViewPager
con unRecycerView
en cada página.onCreateView
, sino después de la carga de datos. Vea la respuesta de @Farmaker aquí.Tienda
Restaurar
y si eso no funciona, intenta
Guarde
onPause()
y restaureonResume()
fuente
lastFirstVisiblePosition
que0
después de restaurarlo. Este caso es útil cuando tiene un fragmento / actividad que carga diferentes datos en unoRecyclerView
, por ejemplo, una aplicación de exploración de archivos.SwipeRefreshLayout
?RecyclerView
Quería guardar la posición de desplazamiento de Recycler View al navegar fuera 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 eran mucho más complicadas de lo necesario o no funcionaban para mi configuración, así que pensé en compartir mi solución.
Primero guarde el estado de su instancia en onPause como muchos lo han mostrado. Creo que vale la pena enfatizar aquí que esta versión de onSaveInstanceState es un método de la clase RecyclerView.LayoutManager.
La clave para que esto funcione correctamente es asegurarse de llamar a onRestoreInstanceState 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.
fuente
Establezco variables en onCreate (), guardo la posición de desplazamiento en onPause () y establezco la posición de desplazamiento en onResume ()
fuente
Ya no tiene que guardar y restaurar el estado usted mismo. Si establece una ID única en xml y reciclaView.setSaveEnabled (verdadero) (verdadero por defecto), el sistema lo hará automáticamente. Aquí hay más sobre esto: http://trickyandroid.com/saving-android-view-state-correctly/
fuente
Todos los administradores de diseño incluidos en la biblioteca de soporte ya saben cómo guardar y restaurar la posición de desplazamiento.
La posición de desplazamiento se restaura en la primera pasada de diseño, lo que ocurre cuando se cumplen las siguientes condiciones:
RecyclerView
RecyclerView
Normalmente, configura el administrador de diseño en XML, por lo que todo lo que tiene que hacer ahora es
RecyclerView
Puede hacer esto en cualquier momento, no está limitado a
Fragment.onCreateView
niActivity.onCreate
.Ejemplo: asegúrese de que el adaptador esté conectado cada vez que se actualicen los datos.
La posición de desplazamiento guardada se calcula a partir de los siguientes datos:
Por lo tanto, puede esperar un ligero desajuste, por ejemplo, si sus artículos tienen diferentes dimensiones en orientación vertical y horizontal.
El
RecyclerView
/ScrollView
/ lo que necesita tener unandroid:id
estado para que se guarde.fuente
LinearLayoutManager.SavedState
: cs.android.com/androidx/platform/frameworks/support/+/…Aquí está mi enfoque para guardarlos y mantener el estado de la vista del reciclaje en un fragmento. Primero, agregue cambios de configuración en su actividad principal como se muestra a continuación.
Luego, en su Fragmento, declare estos métodos de instancia
Agregue el siguiente código en su método @onPause
Agregue el método onConfigartionChanged como se muestra a continuación.
Este enfoque solucionará su problema. Si tiene un administrador de diseño diferente, simplemente reemplace el administrador de diseño superior.
fuente
Así es como restauro la posición de RecyclerView con GridLayoutManager después de la rotación cuando necesita volver a cargar datos de Internet con AsyncTaskLoader.
Cree una variable global de Parcelable y GridLayoutManager y una cadena final estática:
Guardar estado de gridLayoutManager en onSaveInstance ()
Restaurar en onRestoreInstanceState
Luego, cuando el cargador obtiene datos de Internet, restaura la posición de la vista del reciclador en onLoadFinished ()
..por supuesto, debe crear una instancia de gridLayoutManager dentro de onCreate. Salud
fuente
Tuve el mismo requisito, pero las soluciones aquí no me ayudaron a cruzar la línea, debido a la fuente de datos para recyclingView.
Estaba extrayendo el estado LinearLayoutManager de RecyclerViews en onPause ()
Parcelable
state
se guardaonSaveInstanceState(Bundle outState)
y se vuelve a extraer enonCreate(Bundle savedInstanceState)
, cuandosavedInstanceState != null
.Sin embargo, el adaptador de recyclerView se llena y actualiza mediante un objeto ViewModel LiveData devuelto por una llamada DAO a una base de datos de Room.
Finalmente descubrí que restaurar el estado de la instancia directamente después de que los datos se configuran en el adaptador mantendría el estado de desplazamiento en las rotaciones.
Sospecho que esto se debe a que el
LinearLayoutManager
estado que había restaurado se estaba sobrescribiendo cuando los datos fueron devueltos por la llamada a la base de datos, o el estado restaurado no tenía sentido contra un LinearLayoutManager 'vacío'.Si los datos del adaptador están disponibles directamente (es decir, no son contigentes en una llamada a la base de datos), entonces se puede restaurar el estado de la instancia en LinearLayoutManager después de que el adaptador se haya configurado en recyclingView.
La distinción entre los dos escenarios me detuvo durante años.
fuente
En el nivel 28 de la API de Android, simplemente me aseguro de configurar mi método
LinearLayoutManager
yRecyclerView.Adapter
en miFragment#onCreateView
, y todo Just Worked ™ ️. No necesitaba hacer nadaonSaveInstanceState
nionRestoreInstanceState
trabajar.La respuesta de Eugen Pechanec explica por qué funciona.
fuente
A partir de la versión 1.2.0-alpha02 de la biblioteca Androidx RecyclerView, ahora se administra automáticamente. Solo agrégalo con:
Y use:
La enumeración StateRestorationPolicy tiene 3 opciones:
Tenga en cuenta que en el momento de esta respuesta, la biblioteca RecyclerView todavía está en alpha03, pero la fase alfa no es adecuada para fines de producción .
fuente
Para mí, el problema fue que configuré un nuevo administrador de diseño cada vez que cambié mi adaptador, perdiendo la posición de desplazamiento de la cola en la vista de reciclaje.
fuente
Solo me gustaría compartir la situación reciente que encuentro con RecyclerView. Espero que cualquier persona que experimente el mismo problema se beneficie.
Requisito de mi proyecto: Tengo un RecyclerView que enumera algunos elementos en los que se puede hacer clic en mi Actividad principal (Actividad-A). Cuando se hace clic en el elemento, se muestra una nueva actividad con los detalles del elemento (Actividad-B).
Implementé en el archivo de manifiesto que la Actividad-A es el padre de la Actividad-B, de esa manera, tengo un botón de retroceso o inicio en la barra de acciones de la Actividad-B
Problema: cada vez que presioné el botón Atrás o Inicio en la barra de acción de Actividad-B, la Actividad-A entra en el ciclo de vida de actividad completo comenzando desde onCreate ()
Aunque implementé un onSaveInstanceState () guardando la Lista del Adaptador de RecyclerView, cuando Activity-A inicia su ciclo de vida, saveInstanceState siempre es nulo en el método onCreate ().
Investigando más en Internet, encontré el mismo problema, pero la persona notó que el botón Atrás o Inicio debajo del dispositivo Anroid (botón Atrás / Inicio predeterminado), la Actividad-A no entra en el Ciclo de vida de la actividad.
Solución:
Activé el botón de inicio o retroceso en la Actividad-B
En el método onCreate () agregue esta línea supportActionBar? .SetDisplayHomeAsUpEnabled (true)
En el método overide fun onOptionsItemSelected (), verifiqué el item.ItemId en el que se hizo clic en el elemento en función de la identificación. La identificación del botón de retroceso es
android.R.id.home
Luego implemente una llamada a la función finish () dentro de android.R.id.home
Esto finalizará la Actividad-B y traerá la Actividad-A sin pasar por todo el ciclo de vida.
Para mi requerimiento, esta es la mejor solución hasta ahora.
fuente
Tuve el mismo problema con una diferencia menor, estaba usando Databinding y estaba configurando el adaptador RecyclerView y el layoutManager en los métodos de enlace.
El problema era que el enlace de datos estaba sucediendo después de onResume, por lo que estaba restableciendo mi layoutManager después de onResume y eso significa que se estaba desplazando al lugar original cada vez. Entonces, cuando dejé de configurar layoutManager en los métodos del adaptador de enlace de datos, funciona bien nuevamente.
fuente
En mi caso, estaba configurando RecyclerView
layoutManager
tanto en XML como enonViewCreated
. La eliminación de la asignación seonViewCreated
solucionó.fuente
Activity.java:
Por qué estoy usando
OnSaveInstanceState()
inonPause()
significa, mientras que el cambio a otra actividad onPause se llamará. Guardará esa posición de desplazamiento y restaurará la posición cuando regresemos de otra actividad.fuente