Esto se hace mediante la implementación View#onSaveInstanceState
y View#onRestoreInstanceState
y extendiendo la View.BaseSavedState
clase.
public class CustomView extends View {
private int stateToSave;
...
@Override
public Parcelable onSaveInstanceState() {
//begin boilerplate code that allows parent classes to save state
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
//end
ss.stateToSave = this.stateToSave;
return ss;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
//begin boilerplate code so parent classes can restore state
if(!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState)state;
super.onRestoreInstanceState(ss.getSuperState());
//end
this.stateToSave = ss.stateToSave;
}
static class SavedState extends BaseSavedState {
int stateToSave;
SavedState(Parcelable superState) {
super(superState);
}
private SavedState(Parcel in) {
super(in);
this.stateToSave = in.readInt();
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(this.stateToSave);
}
//required field that makes Parcelables from a Parcel
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}
El trabajo se divide entre la vista y la clase SavedState de la vista. Debes hacer todo el trabajo de lectura y escritura desde y hacia Parcel
la SavedState
clase. Luego, su clase View puede hacer el trabajo de extraer los miembros del estado y hacer el trabajo necesario para que la clase vuelva a un estado válido.
Notas: View#onSavedInstanceState
y se View#onRestoreInstanceState
les llama automáticamente si View#getId
devuelve un valor> = 0. Esto sucede cuando le da una identificación en xml o llama setId
manualmente. De lo contrario, usted tiene que llamar View#onSaveInstanceState
y escribir el parcelable regresó a la parcela que se obtiene en Activity#onSaveInstanceState
guardar el estado y posteriormente leerlo y pasarlo a View#onRestoreInstanceState
partir Activity#onRestoreInstanceState
.
Otro ejemplo simple de esto es el CompoundButton
onSaveInstanceState()
yonRestoreInstanceState()
debería serprotected
(como su superclase), nopublic
. No hay razón para exponerlos ...BaseSaveState
para una clase que extiende RecyclerView, porParcel﹕ Class not found when unmarshalling: android.support.v7.widget.RecyclerView$SavedState java.lang.ClassNotFoundException: android.support.v7.widget.RecyclerView$SavedState
lo que debe hacer la corrección de errores que está escrita aquí: github.com/ksoichiro/Android-ObservableScrollView/commit/… (usando el ClassLoader de RecyclerView.class para cargar el súper estado)Creo que esta es una versión mucho más simple.
Bundle
es un tipo incorporado que implementaParcelable
fuente
onRestoreInstanceState
se llamaría con un paquete si seonSaveInstanceState
devuelve un paquete?OnRestoreInstance
es heredado No podemos cambiar el encabezado.Parcelable
es solo una interfaz,Bundle
es una implementación para eso.View
estado base no es unBundle
. Por supuesto, eso es cierto en este momento, pero usted confía en este hecho de implementación actual que no se garantiza que sea cierto.Aquí hay otra variante que utiliza una combinación de los dos métodos anteriores. Combinando la velocidad y la corrección de
Parcelable
con la simplicidad de unBundle
:fuente
State
paquete. Por favor, eche un vistazo a: charlesharley.com/2012/programming/…Las respuestas aquí ya son geniales, pero no necesariamente funcionan para grupos de vista personalizados. Para que todas las Vistas personalizadas conserven su estado, debe anular
onSaveInstanceState()
yonRestoreInstanceState(Parcelable state)
en cada clase. También debe asegurarse de que todos tengan identificadores únicos, ya sea que estén inflados desde xml o agregados mediante programación.Lo que se me ocurrió fue notablemente como la respuesta de Kobor42, pero el error se mantuvo porque estaba agregando las Vistas a un Grupo de Vistas personalizado mediante programación y no asignando identificadores únicos.
El enlace compartido por mato funcionará, pero significa que ninguna de las Vistas individuales gestiona su propio estado: todo el estado se guarda en los métodos ViewGroup.
El problema es que cuando se agregan múltiples de estos ViewGroups a un diseño, los identificadores de sus elementos del xml ya no son únicos (si está definido en xml). En tiempo de ejecución, puede llamar al método estático
View.generateViewId()
para obtener una identificación única para una vista. Esto solo está disponible en API 17.Aquí está mi código del ViewGroup (es abstracto, y mOriginalValue es una variable de tipo):
fuente
Tuve el problema de que onRestoreInstanceState restauró todas mis vistas personalizadas con el estado de la última vista. Lo resolví agregando estos dos métodos a mi vista personalizada:
fuente
En lugar de usar
onSaveInstanceState
yonRestoreInstanceState
, también puede usar aViewModel
. Extienda su modelo de datosViewModel
y luego puede usarloViewModelProviders
para obtener la misma instancia de su modelo cada vez que se recrea la Actividad:Para usar
ViewModelProviders
, agregue lo siguiente adependencies
enapp/build.gradle
:Tenga en cuenta que su
MyActivity
extiende enFragmentActivity
lugar de solo extenderActivity
.Puede leer más sobre ViewModels aquí:
fuente
ViewModel
es especialmente útil si tiene grandes conjuntos de datos para retener durante un cambio de estado, como una rotación de pantalla. Prefiero usar el enViewModel
lugar de escribirloApplication
porque tiene un alcance claro, y puedo tener múltiples actividades de la misma aplicación comportándose correctamente.Descubrí que esta respuesta estaba causando algunos bloqueos en las versiones de Android 9 y 10. Creo que es un buen enfoque, pero cuando estaba buscando un código de Android descubrí que le faltaba un constructor. La respuesta es bastante antigua, por lo que en ese momento probablemente no haya sido necesaria. Cuando agregué el constructor faltante y lo llamé desde el creador, se solucionó el bloqueo.
Así que aquí está el código editado:
fuente
Para aumentar otras respuestas: si tiene varias vistas compuestas personalizadas con la misma ID y todas están siendo restauradas con el estado de la última vista en un cambio de configuración, todo lo que necesita hacer es decirle a la vista que solo envíe eventos de guardar / restaurar a sí mismo anulando un par de métodos.
Para una explicación de lo que está sucediendo y por qué esto funciona, vea esta publicación de blog . Básicamente, cada vista compuesta comparte las ID de vista de los niños de su vista compuesta y la restauración del estado se confunde. Al enviar solo el estado para la vista compuesta en sí, evitamos que sus hijos reciban mensajes mixtos de otras vistas compuestas.
fuente