mardi 21 février 2012

Sauvegarder l'état des variables d'une activité Android lors de la rotation

Si vous développez des appli Android, il vous est sûrement déjà arrivé de devoir remplir passer des données d'une activité à une autre, et de vous apercevoir que lorsque vous tourniez votre téléphone les données du bundle étaient perdues.

Cela est une problématique classique du cycle de vie d'une activité sur Android. En effet, lors d'une rotation, votre activité est détruite, et elle se rappelle elle-même en quelque sorte. De ce faite, toutes les données qui avaient été stockées dans les variables automatiques sont initialisées à nouveau. Une façon de conserver ces données serait de passer les variables en statiques, et c'est une erreur que je considérerais de débutant, que j'ai faite à mes débuts. Sur le principe cela fonctionne, mais le code n'est pas propre.

Le meilleure pratique est, je pense, de considérer la surcharge de la méthode onSaveInstanceState(Bundle icicle) de la classe Activity. Prenons une activité classique:

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;


public class testActivity extends Activity
{
 
 String test;
 
 @Override
 protected void onCreate(Bundle savedInstanceState)
 {
  super.onCreate(savedInstanceState);
  test = getIntent().getExtras().getString("test", "test perdu");
  Log.d("test bundle", test);
 }

}

Si vous avez lancé l'activité depuis une autre activité de cette façon:

Intent i = new Intent(this, testActivity.class);
i.putExtra("test", "test ok");
startActivity(i);

Votre logcat va afficher test ok.
Si vous faites une rotation de l'écran, votre logcat affiche test perdu. C'est là qu'intervient onSaveInstanceState(Bundle icicle). Celui-ci va être appelé avant la destruction de l'activité. Nous allons donc l'implémenter ainsi:

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class testActivity extends Activity
{
 String test;

 @Override
 protected void onCreate(Bundle savedInstanceState)
 {
  super.onCreate(savedInstanceState);

  test = getIntent().getExtras().getString("test");
  if (test == null) savedInstanceState.getString("test", "test non défini");

  Log.d("test bundle", test);
 }

 @Override
 protected void onSaveInstanceState(Bundle outState)
 {
  outState.putString("test", test);
  super.onSaveInstanceState(outState);
 }

}

Comme on peut le voir ici, on place dans le bundle outState toutes les données que l'on veut sauvegarder. Nous avons légèrement modifier le traitement de la méthode onCreate(Bundle savedInstanceState) pour récupérer ces données que nous avons stockée dans outState. Donc on récupère, par exemple, les extras qui auraient du être passés par l'activité précédente. Si ces extras ont disparu à la rotation, on regarde si l'on ne peut pas les récupérer dans le savedInstanceState, qui est une copie du bundle outState précédent.

Bien sûr, cela ne fonctionne pas qu'avec les String, toutes les données stockables dans un bundle peuvent être sauvegardées dans outState de onSaveInstance et récupérée dans le savedInstance de onCreate après la rotation.

Vous pouvez désormais vous passer de ces vilaines variables statiques que l'on ne saurait voir et faire des rotations d'activité en conservant vos données :)

Twitter