Laisser Android gérer la rotation mais sauver l'état de l'activité
Contrairement à la première solution où l'idée était de bloquer toutes rotations de l'écran (Interdire la rotation), ici, vous allez laisser la rotation s'effectuer via Android. Cependant, dans cette solution, votre activité sera supprimée.
La raison étant liée au fait que l'affichage de l'activité change (de portrait au mode paysage ou inversement). Ce qui implique que tout le contenu de l'écran (vue) avant rotation doit être redessiné pour pouvoir être affichable dans le nouveau mode.
layout-land
Jusqu'à présent, le dessin de votre vue était effectué dans res/layout. Ce répertoire contenant les vues de vos différentes activités.
Pour associer une activité à une vue, vous utiliserez la méthode setContentView().
Pour dessiner les vues de vos activités spécifiquement au mode paysage, vous utiliserez res/layout-land. Par contre, le but étant initialement de laisser faire Android, vous n'aurez qu'une contrainte: utiliser le même nom de vue que celle du mode portrait.
Vous n'aurez ainsi rien à faire dans le setContentView(). Android recherchant tout seul la vue correspondante dans res/layout-land. S'il ne l'a trouve pas, alors utilisation de celle présente dans res/layout. (cf. Différents fichiers de configurations pour différents types d'écrans)
Voici un exemple fr.free.supertos.helloworld
Le fichier MainActivity.java
Le fichier activity_main.xml dans res/layout
Vous préciserez dans quelle orientation devront être dessinés les widgets du layout (android:orientation).
En vertical pour le mode portrait
et dans res/layout-land (orientation horizontale pour le paysage).
Pour bien différencier
les deux vues, la taille du texte sera plus importante en paysage qu'en portrait,
d'où le fichier suivant dimens.xml du répertoire values:
Autres solution
en plus de strings.xml
et enfin le fichier AndroidManifest.xml qui n'a rien de particulier
Destruction de l'activité lors de la rotation
Le problème est que votre activité sera supprimée lors de la détection de la rotation par Android. Rien de dramatique cependant, car elle sera automatiquement relancée...sauf que vos données seront perdues !
Là encore, il y a une solution:
Votre activité passe forcement par les différentes étapes du cycle de vie des activites.
Une phase n'est cependant pas apparente: onSaveInstanceState(), et pour cause, elle est un peu particulière...
Cette méthode n'est appelée que si Android pour une raison (justement particulière) doit tuer l'activité pour la relancer dans un état plus cohérent avec son environnement. Et c'est le cas avec la rotation de l'écran (autre cas, mémoire qui devient insuffisante, ou encore si l'activité passe en arrière plan (intention, StartActivity par exemple). Ainsi, si l'activité est détruite, la relance de l'activité passera forcement par onCreate() qui pourra restaurer les valeurs des variables mémorisées).
Cette méthode
ne remplace nullement la méthode onPause()
La méthode onSaveInstanceState() a en paramètre un bundle que vous pourrez alimenter avec les données à sauver pour la relance de l'activité.
protected void onSaveInstanceState(Bundle saveInstanceState) {
super.onSaveInstanceState(saveInstanceState);[...Votre code ici...]
saveInstanceState.putString("clef", "valeur");
et tous les types possibles...
}
"Petite" liste des put possibles:
void putAll(Bundle bundle)
void putBinder(String key, IBinder value)
void putBundle(String key, Bundle value)
void putByte(String key, byte value)
void putByteArray(String key, byte[] value)
void putChar(String key, char value)
void putCharArray(String key, char[] value)
void putCharSequence(String key, CharSequence value)
void putCharSequenceArray(String key, CharSequence[] value)
void putCharSequenceArrayList(String key, ArrayList<CharSequence> value)
void putFloat(String key, float value)
void putFloatArray(String key, float[] value)
void putIntegerArrayList(String key, ArrayList<Integer> value)
void putParcelable(String key, Parcelable value)
void putParcelableArray(String key, Parcelable[] value)
void putParcelableArrayList(String key, ArrayList<? extends Parcelable>
value)
void putSerializable(String key, Serializable value)
void putShort(String key, short value)
void putShortArray(String key, short[] value)
void putSize(String key, Size value)
void putSizeF(String key, SizeF value)
void putSparseParcelableArray(String key, SparseArray<? extends Parcelable>
value)
void putStringArrayList(String key, ArrayList<String> value)
Lorsque votre activité est recréée, elle repasse par le cycle de vie normal et donc par le onCreate.
Or cette méthode reçoit un bundle en paramètre, celui initialisé (éventuellement) par le onSaveInstanteState justement !
Si ce paramètre est null, il s'agit d'une création d'activité normale. Si différent de zéro, il s'agit d'une relance de l'activité.
il est fréquent
de trouver une méthode restoreMe(Bundle state) dans l'activité
appelée lors du onCreate pour restaurer les données. Le nom n'est
évidemment pas imposé !
private void restoreMe(Bundle state) {
/* initialisation des variables ici */[...]
if (state!=null) { // Le bundle existe donc:
// Restauration des données
var=state.getString ("clef") etc...
// Et tous les get possibles...
}
}
IBinder getBinder(String key)
Bundle getBundle(String key)
byte getByte(String key)
Byte getByte(String key, byte defaultValue)
byte[] getByteArray(String key)
char getChar(String key)
char getChar(String key, char defaultValue)
char[] getCharArray(String key)
CharSequence getCharSequence(String key, CharSequence defaultValue)
CharSequence getCharSequence(String key)
CharSequence[] getCharSequenceArray(String key)
ArrayList<CharSequence> getCharSequenceArrayList(String key)
ClassLoader getClassLoader()
float getFloat(String key)
float getFloat(String key, float defaultValue)
float[] getFloatArray(String key)
ArrayList<Integer> getIntegerArrayList(String key)
<T extends Parcelable> T getParcelable(String key)
Parcelable[] getParcelableArray(String key)
<T extends Parcelable> ArrayList<T> getParcelableArrayList(String
key)
Serializable getSerializable(String key)
short getShort(String key)
short getShort(String key, short defaultValue)
short[] getShortArray(String key)
Size getSize(String key)
SizeF getSizeF(String key)
<T extends Parcelable> SparseArray<T> getSparseParcelableArray(String
key)
ArrayList<String> getStringArrayList(String key)
Les problèmes de cette solution
Il s'agit d'un bundle, donc limité en taille et certaines informations ne pourront pas être stockées.
La sérialisation des objets reste par exemple intéressante pour certains cas.
Une autre solution consistera à utiliser la méthode public Object onRetainNonConfigurationInstance() à la place de onSaveInstanceState().
Cette méthode va permettre de récupérer un objet (Thread, sockets, ... tout ce qui n'est pas détruit).
Lors de l'exécution de la méthode onCreate(), il suffira d'utiliser getLastNonConfigurationInstance() pour récupérer votre objet ou null s'il n'y a rien à récupérer.