Cómo evitar que las vistas personalizadas pierdan estado debido a los cambios de orientación de la pantalla
Implementé con éxito onRetainNonConfigurationInstance()
que mi principal Activity
guarde y restaure ciertos componentes críticos a través de los cambios de orientación de la pantalla.
Pero parece que mis vistas personalizadas se recrean desde cero cuando cambia la orientación. Esto tiene sentido, aunque en mi caso es un inconveniente porque la vista personalizada en cuestión es un gráfico X/Y y los puntos trazados se almacenan en la vista personalizada.
¿Existe una forma ingeniosa de implementar algo similar a onRetainNonConfigurationInstance()
una vista personalizada, o necesito simplemente implementar métodos en la vista personalizada que me permitan obtener y establecer su "estado"?
Creo que esta es una versión mucho más simple. Bundle
es un tipo incorporado que implementaParcelable
public class CustomView extends View
{
private int stuff; // stuff
@Override
public Parcelable onSaveInstanceState()
{
Bundle bundle = new Bundle();
bundle.putParcelable("superState", super.onSaveInstanceState());
bundle.putInt("stuff", this.stuff); // ... save stuff
return bundle;
}
@Override
public void onRestoreInstanceState(Parcelable state)
{
if (state instanceof Bundle) // implicit null check
{
Bundle bundle = (Bundle) state;
this.stuff = bundle.getInt("stuff"); // ... load stuff
state = bundle.getParcelable("superState");
}
super.onRestoreInstanceState(state);
}
}
Para ello, implemente View#onSaveInstanceState
y View#onRestoreInstanceState
amplíe 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 clase View y SavedState de la View. Debes hacer todo el trabajo de lectura y escritura hacia y desde 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 View#onRestoreInstanceState
se llaman automáticamente si View#getId
devuelve un valor>= 0. Esto sucede cuando le proporciona una identificación en xml o lo llama setId
manualmente. En caso contrario tienes que llamar View#onSaveInstanceState
y escribir el Parcelable devuelto al paquete que recibes Activity#onSaveInstanceState
para guardar el estado y posteriormente leerlo y pasarlo a View#onRestoreInstanceState
desde Activity#onRestoreInstanceState
.
Otro ejemplo sencillo de esto es elCompoundButton