web-dev-qa-db-fra.com

Gérer la rotation de l'écran sans perdre de données - Android

Je deviens fou de trouver la meilleure façon de gérer la rotation de l'écran. J'ai lu des centaines de questions/réponses ici mais je suis vraiment confus.

Comment puis-je enregistrer les données myClass avant que l'activité ne soit recréée afin que je puisse tout conserver pour redessiner l'activité sans autre initialisation inutile?

Existe-t-il un moyen plus propre et meilleur que le colis?

J'ai besoin de gérer la rotation parce que je veux changer la disposition en mode paysage.

public class MtgoLifecounterActivity extends Activity {

    MyClass myClass;

    // Called when the activity is first created
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        If ( ?? first run...myClass == null ? ) {
            myClass = new MyClass();
        } else {
            // do other stuff but I need myClass istance with all values.
        }
        // I want that this is called only first time. 
        // then in case of rotation of screen, i want to restore the other instance of myClass which
        // is full of data.
    }
38
Riccardo Neri

peut utiliser la méthode de remplacement onSaveInstanceState() et onRestoreInstanceState(). ou pour arrêter d'appeler onCreate() sur la rotation de l'écran, ajoutez simplement cette ligne dans votre manifeste xml Android:configChanges="keyboardHidden|orientation"

note: votre classe personnalisée doit implémenter Parcelable exemple ci-dessous.

@Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putParcelable("obj", myClass);
    }

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
 // TODO Auto-generated method stub
 super.onRestoreInstanceState(savedInstanceState);
 myClass=savedInstanceState.getParcelable("obj"));
}

public class MyParcelable implements Parcelable {
     private int mData;

 public int describeContents() {
     return 0;
 }

 /** save object in parcel */
 public void writeToParcel(Parcel out, int flags) {
     out.writeInt(mData);
 }

 public static final Parcelable.Creator<MyParcelable> CREATOR
         = new Parcelable.Creator<MyParcelable>() {
     public MyParcelable createFromParcel(Parcel in) {
         return new MyParcelable(in);
     }

     public MyParcelable[] newArray(int size) {
         return new MyParcelable[size];
     }
 };

 /** recreate object from parcel */
 private MyParcelable(Parcel in) {
     mData = in.readInt();
 }


}
26
Azhar Shaikh

Dans la balise d'activité du manifeste, vous devez mentionner

<activity
        Android:name="com.example.ListActivity"
        Android:label="@string/app_name" 
        Android:configChanges="keyboardHidden|orientation">

Si vous utilisez Android 2.3 (API niveau 13) et au-dessus, utilisez

<activity
        Android:name="com.example.Activity"
        Android:label="@string/app_name" 
        Android:configChanges="keyboardHidden|orientation|screenSize">

Cela devrait fonctionner.

Cela ne fonctionnera qu'avec activité tag et non avec application tag

42
Cool7

Peut-être que cela est déjà résolu mais juste pour une petite mise à jour pour les nouveaux membres qui s'y sont accrochés, jetez un œil à Google Developer Site , à partir du niveau 13 de l'API, il vous suffit d'ajouter ce code à Manifest :

<activity Android:name=".SplashScreensActivity"
          Android:configChanges="orientation|keyboardHidden|screenSize"
          Android:label="@string/app_name">

lorsqu'une de ces configurations change, SplashScreensActivity ne redémarre pas. Au lieu de cela, le SplashScreensActivity reçoit un appel à onConfigurationChanged (). Cette méthode reçoit un objet Configuration qui spécifie la nouvelle configuration de périphérique. En lisant les champs de la configuration, vous pouvez déterminer la nouvelle configuration et apporter les modifications appropriées en mettant à jour les ressources utilisées dans votre interface. Au moment où cette méthode est appelée, l'objet Resources de votre activité est mis à jour pour renvoyer des ressources en fonction de la nouvelle configuration, de sorte que vous pouvez facilement réinitialiser des éléments de votre interface utilisateur sans que le système ne redémarre votre activité.

15
Zak Chapman

Le problème ici est que vous perdez "l'état" de l'application. Dans les POO, qu'est-ce qu'un État? Les variables! Exactement! Par conséquent, lorsque vous perdez les données de vos variables.

Maintenant, voici ce que vous pouvez faire, Découvrez les variables qui perdent leurs états.

enter image description here

Lorsque vous faites pivoter votre appareil, votre activité actuelle est complètement détruite, c'est-à-dire qu'elle passe par onSaveInstanceState () onPause() onStop() onDestroy() et une nouvelle activité est créée complètement qui passe par onCreate() onStart() onRestoreInstanceState .

Les deux méthodes en gras, onSaveInstanceState () enregistre l'instance de l'activité actuelle qui va être détruite. onRestoreInstanceState Cette méthode restaure l'état enregistré de l'activité précédente. De cette façon, vous ne perdez pas votre état précédent de l'application.

Voici comment vous utilisez ces méthodes.

 @Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);

        outState.putString("theWord", theWord); // Saving the Variable theWord
        outState.putStringArrayList("fiveDefns", fiveDefns); // Saving the ArrayList fiveDefns
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState, PersistableBundle persistentState) {
        super.onRestoreInstanceState(savedInstanceState, persistentState);

        theWord = savedInstanceState.getString("theWord"); // Restoring theWord
        fiveDefns = savedInstanceState.getStringArrayList("fiveDefns"); //Restoring fiveDefns
    }

EDIT: Une meilleure approche: L'approche ci-dessus pour la maintenance de vos données n'est pas la meilleure façon de conserver les données dans le code de production/applications. Google IO 2017 a introduit ViewModel pour protéger vos données contre les changements de configuration (comme la rotation d'écran). Garder toutes les données à l'intérieur de l'activité en utilisant des variables n'est pas une bonne conception logicielle et viole le Single Principe de responsabilité séparez donc votre stockage de données à l'aide de ViewModel des activités.

  • ViewModel sera responsable des données à afficher.
  • L'activité sera responsable de la façon d'afficher les données.
  • Utilisez une classe de référentiel supplémentaire si vous avez une complexité croissante de stockage des données.

Ce n'est qu'un moyen de séparer les classes et leur responsabilité, qui ira un long chemin tout en créant des applications bien architecturées.

13
devDeejay

Il y a deux (bonnes) façons de procéder. Faites en sorte que votre classe implémente Parcelable et placez-la dans un bundle dans onSaveInstanceState(), ou, si elle est plus complexe (par exemple une AsyncTask), renvoyez-la dans onRetainNonConfigurationInstance().

Ensuite, il y a aussi la manière paresseuse où vous arrêtez simplement de réagir aux changements de configuration.

4
dmon

Si vous n'avez pas besoin de redémarrer votre activité, définissez simplement l'attribut configChanges sur votre activité dans AndroidManifest.xml comme suit:

    Android:configChanges="keyboard|keyboardHidden|orientation"

Cela indiquera au système d'exploitation que vous allez vous occuper de la gestion d'une rotation et ne redémarrera pas votre activité. L'utilisation de cette méthode supprimera la nécessité de sauvegarder tout type d'état.

3
Bobbake4