Cómo evitar que las vistas personalizadas pierdan estado debido a los cambios de orientación de la pantalla

Resuelto Brad Hein asked hace 54 años • 10 respuestas

Implementé con éxito onRetainNonConfigurationInstance()que mi principal Activityguarde 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"?

Brad Hein avatar Jan 01 '70 08:01 Brad Hein
Aceptado

Creo que esta es una versión mucho más simple. Bundlees 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);
  }
}
Kobor42 avatar Nov 14 '2011 20:11 Kobor42

Para ello, implemente View#onSaveInstanceStatey View#onRestoreInstanceStateamplíe la View.BaseSavedStateclase.

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 Parcella SavedStateclase. 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#onSavedInstanceStatey View#onRestoreInstanceStatese llaman automáticamente si View#getIddevuelve un valor>= 0. Esto sucede cuando le proporciona una identificación en xml o lo llama setIdmanualmente. En caso contrario tienes que llamar View#onSaveInstanceStatey escribir el Parcelable devuelto al paquete que recibes Activity#onSaveInstanceStatepara guardar el estado y posteriormente leerlo y pasarlo a View#onRestoreInstanceStatedesde Activity#onRestoreInstanceState.

Otro ejemplo sencillo de esto es elCompoundButton

Rich Schuler avatar Aug 22 '2010 19:08 Rich Schuler