Pour ce faire , la mise en œuvre View#onSaveInstanceState
et View#onRestoreInstanceState
et l' extension de la View.BaseSavedState
classe.
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];
}
};
}
}
Le travail est divisé entre la classe View et la classe SavedState de la vue. Vous devriez faire tout le travail de lecture et d'écriture vers et depuis Parcel
le SavedState
cours. Ensuite, votre classe View peut effectuer le travail d'extraction des membres de l'état et effectuer le travail nécessaire pour ramener la classe à un état valide.
Remarques: View#onSavedInstanceState
et View#onRestoreInstanceState
sont appelés automatiquement pour vous si View#getId
renvoie une valeur> = 0. Cela se produit lorsque vous lui donnez un identifiant en xml ou appelez setId
manuellement. Sinon , vous devez appeler View#onSaveInstanceState
et écrire le Parcelable retourné au colis que vous obtenez dans Activity#onSaveInstanceState
d'enregistrer l'état et de lire la suite et le transmettre à View#onRestoreInstanceState
partir Activity#onRestoreInstanceState
.
Un autre exemple simple de ceci est le CompoundButton
onSaveInstanceState()
etonRestoreInstanceState()
devrait êtreprotected
(comme leur superclasse), nonpublic
. Aucune raison de les exposer ...BaseSaveState
pour une classe qui étend RecyclerView, vous obtenezParcel﹕ Class not found when unmarshalling: android.support.v7.widget.RecyclerView$SavedState java.lang.ClassNotFoundException: android.support.v7.widget.RecyclerView$SavedState
donc vous devez faire le correctif de bogue qui est écrit ici: github.com/ksoichiro/Android-ObservableScrollView/commit/… (en utilisant le ClassLoader de RecyclerView.class pour charger le super état)Je pense que c'est une version beaucoup plus simple.
Bundle
est un type intégré qui implémenteParcelable
la source
onRestoreInstanceState
appelé avec un Bundle si je lui rendaisonSaveInstanceState
un Bundle?OnRestoreInstance
est hérité. Nous ne pouvons pas changer l'en-tête.Parcelable
est juste une interface,Bundle
est une implémentation pour cela.View
état de base n'est pas aBundle
. Bien sûr, c'est vrai pour le moment, mais vous comptez sur ce fait de mise en œuvre actuel qui n'est pas garanti d'être vrai.Voici une autre variante qui utilise un mélange des deux méthodes ci-dessus. Combiner la vitesse et la justesse de
Parcelable
avec la simplicité d'unBundle
:la source
State
partir du colis. Veuillez consulter: charlesharley.com/2012/programming/…Les réponses ici sont déjà excellentes, mais ne fonctionnent pas nécessairement pour les ViewGroups personnalisés. Pour que toutes les vues personnalisées conservent leur état, vous devez remplacer
onSaveInstanceState()
etonRestoreInstanceState(Parcelable state)
dans chaque classe. Vous devez également vous assurer qu'ils ont tous des identifiants uniques, qu'ils soient gonflés à partir de XML ou ajoutés par programme.Ce que j'ai trouvé ressemblait remarquablement à la réponse de Kobor42, mais l'erreur est restée parce que j'ajoutais les vues à un ViewGroup personnalisé par programme et que je n'attribuais pas d'identifiants uniques.
Le lien partagé par mato fonctionnera, mais cela signifie qu'aucune des vues individuelles ne gère son propre état - l'état entier est enregistré dans les méthodes ViewGroup.
Le problème est que lorsque plusieurs de ces ViewGroups sont ajoutés à une mise en page, les identifiants de leurs éléments du XML ne sont plus uniques (s'ils sont définis en XML). Au moment de l'exécution, vous pouvez appeler la méthode statique
View.generateViewId()
pour obtenir un identifiant unique pour une vue. Ceci n'est disponible qu'à partir de l'API 17.Voici mon code du ViewGroup (il est abstrait et mOriginalValue est une variable de type):
la source
J'ai eu le problème que onRestoreInstanceState a restauré toutes mes vues personnalisées avec l'état de la dernière vue. Je l'ai résolu en ajoutant ces deux méthodes à ma vue personnalisée:
la source
Au lieu d'utiliser
onSaveInstanceState
etonRestoreInstanceState
, vous pouvez également utiliser aViewModel
. Faites étendre votre modèle de donnéesViewModel
, puis vous pouvez utiliserViewModelProviders
pour obtenir la même instance de votre modèle chaque fois que l'activité est recréée:Pour l'utiliser
ViewModelProviders
, ajoutez les éléments suivantsdependencies
dansapp/build.gradle
:Notez que votre
MyActivity
étendFragmentActivity
au lieu de simplement s'étendreActivity
.Vous pouvez en savoir plus sur ViewModels ici:
la source
ViewModel
est particulièrement pratique si vous avez de grands ensembles de données à conserver lors d'un changement d'état, comme une rotation d'écran. Je préfère utiliser leViewModel
au lieu de l'écrireApplication
car il est clairement défini et je peux avoir plusieurs activités de la même application se comportant correctement.Je l'ai trouvé cette réponse provoquait des plantages sur les versions 9 et 10 d'Android. Je pense que c'est une bonne approche mais quand j'ai regardé du code Android, j'ai découvert qu'il manquait un constructeur. La réponse est assez ancienne, donc à l'époque, elle n'était probablement pas nécessaire. Quand j'ai ajouté le constructeur manquant et l'ai appelé du créateur, le crash a été corrigé.
Voici donc le code édité:
la source
Pour augmenter les autres réponses - si vous avez plusieurs vues composées personnalisées avec le même ID et qu'elles sont toutes en cours de restauration avec l'état de la dernière vue lors d'un changement de configuration, tout ce que vous devez faire est de dire à la vue de ne distribuer que les événements de sauvegarde / restauration à lui-même en remplaçant un couple de méthodes.
Pour une explication de ce qui se passe et pourquoi cela fonctionne, consultez cet article de blog . Fondamentalement, les ID de vue des enfants de votre vue composée sont partagés par chaque vue composée et la restauration de l'état est confuse. En ne répartissant l'état que pour la vue composée elle-même, nous empêchons leurs enfants d'obtenir des messages mixtes provenant d'autres vues composées.
la source