Redémarrage de l'activité sur rotation Android

1381

Dans mon application Android, lorsque je fais pivoter l'appareil (faites glisser le clavier), mon Activityest redémarré ( onCreateest appelé). Maintenant, c'est probablement comme ça que ça devrait être, mais je fais beaucoup de configuration initiale dans la onCreateméthode, j'ai donc besoin soit:

  1. Mettez toute la configuration initiale dans une autre fonction afin que tout ne soit pas perdu lors de la rotation de l'appareil ou
  2. Faites en sorte qu'il onCreatene soit pas appelé à nouveau et la mise en page se règle simplement ou
  3. Limitez l'application à un simple portrait afin qu'elle onCreatene soit pas appelée.
Isaac Waller
la source
4
Il y a une explication plutôt complète sur la façon de conserver les tâches asynchrones de longue durée lors des changements de configuration d'activité dans ce blog aussi!
Adrian Monk
3
Ce n'est pas une réponse directe comme d'autres l'ont déjà répondu, mais je vous invite à jeter un œil à LogLifeCycle pour comprendre ce qui se passe dans vos applications Android concernant les cycles de vie.
Snicolas

Réponses:

965

Utilisation de la classe d'application

Selon ce que vous faites dans votre initialisation, vous pouvez envisager de créer une nouvelle classe qui étend Applicationet de déplacer votre code d'initialisation dans une onCreateméthode redéfinie au sein de cette classe.

public class MyApplicationClass extends Application {
  @Override
  public void onCreate() {
    super.onCreate();
    // TODO Put your application initialization code here.
  }
}

Dans onCreatela classe d'application est appelé uniquement lorsque l'application entière est créée, de sorte que l'activité redémarre lors de changements d'orientation ou de visibilité du clavier ne la déclenchera pas.

Il est recommandé d'exposer l'instance de cette classe en tant que singleton et d'exposer les variables d'application que vous initialisez à l'aide de getters et setters.

REMARQUE: vous devrez spécifier le nom de votre nouvelle classe d'application dans le manifeste pour qu'elle soit enregistrée et utilisée:

<application
    android:name="com.you.yourapp.MyApplicationClass"

Réagir aux changements de configuration [MISE À JOUR: ceci est obsolète depuis l'API 13; voir l'alternative recommandée ]

Comme alternative, vous pouvez demander à votre application d'écouter les événements qui provoqueraient un redémarrage - comme les changements d'orientation et de visibilité du clavier - et de les gérer dans votre activité.

Commencez par ajouter le android:configChangesnœud au nœud manifeste de votre activité

 <activity android:name=".MyActivity"
      android:configChanges="orientation|keyboardHidden"
      android:label="@string/app_name">

ou pour Android 3.2 (API niveau 13) et plus récent :

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

Ensuite, dans l'activité, remplacez la onConfigurationChangedméthode et appelez setContentViewpour forcer la disposition de l'interface graphique à refaire dans la nouvelle orientation.

@Override
public void onConfigurationChanged(Configuration newConfig) {
  super.onConfigurationChanged(newConfig);
  setContentView(R.layout.myLayout);
}
Reto Meier
la source
17
Je ne pense pas que la deuxième approche fonctionne. Je l'ai essayé; une activité avec un EditText. J'ai écrit du texte là-bas, changé d'orientation et le texte était parti / réinitialisé.
Ted
231
Espérons que nous verrons une méthode onRotate () à l'avenir. Avoir même à se soucier de choses comme ça est - franchement - frustrant.
Kelly Sutton
84
Notez que le Guide du développeur Android met en garde contre l'utilisation de ceci: Remarque: L'utilisation de ( android:configChanges) doit être évitée et utilisée uniquement en dernier recours. Veuillez lire Gestion des modifications du runtime pour plus d'informations sur la façon de gérer correctement un redémarrage en raison d'un changement de configuration. Au lieu de cela, pour conserver les données sur les événements de rotation, ils semblent préférer utiliser le onSaveInstanceState Bundle; ou @ Jon-O mentionne , onRetainNonConfigurationInstance.
Jeffro
19
C'est une mauvaise solution, car elle ne réagit qu'aux modifications de configuration actuellement connues . Avec les nouvelles versions d'Android, d'autres modifications de configuration peuvent se produire que ce code ne détectera pas (car il doit répertorier toutes les modifications de configuration dans le manifeste). La solution consistant à enregistrer l'état avec onRetainNonConfigurationChangesest plus tolérante aux pannes et simple.
Bananeweizen
16
Je pense que vous devriez ajouter cette mise à jour sur 3.2 à votre réponse, elle est assez importante (juste face à ce problème) et elle pourrait être négligée.
bigstones
185

Mise à jour pour Android 3.2 et supérieur:

Attention : à partir d'Android 3.2 (API niveau 13), la "taille de l'écran" change également lorsque l'appareil bascule entre l'orientation portrait et paysage. Ainsi, si vous souhaitez empêcher les redémarrages de l'exécution en raison d'un changement d'orientation lors du développement pour l'API de niveau 13 ou supérieur (comme déclaré par les attributs minSdkVersion et targetSdkVersion), vous devez inclure la "screenSize"valeur en plus de la "orientation"valeur. Autrement dit, vous devez déclarer android:configChanges="orientation|screenSize". Cependant, si votre application cible l'API de niveau 12 ou inférieur, votre activité gère toujours cette modification de configuration elle-même (cette modification de configuration ne redémarre pas votre activité, même lorsqu'elle s'exécute sur un appareil Android 3.2 ou supérieur).

Gorm
la source
1
Merci pour cette précision, car un commentaire ci-dessus m'a presque renvoyé pour y réfléchir. Je cible actuellement l'API 8 et mon code n'a pas screenSize sur configChanges et peut confirmer qu'il fonctionne correctement (sans réorienter) sur le périphérique que je possède qui exécute ICS.
Carl
Merci de l'avoir signalé, je n'avais que android: configChanges = "orientation | screenSize", et le changement d'orientation recréait mon activité, et pour la vie de moi, je n'ai pas pu comprendre pourquoi!
Christopher Perry
5
Ajouter android: configChanges ne doit être utilisé qu'en dernier recours . Pensez à utiliser Fragmentset à la setRetainInstanceplace.
Simon Forsberg
Le point clé est screenSizepour Android 3.2 et supérieur, qui a résolu mon problème, merci!
fantouch
127

Au lieu d'essayer d'empêcher onCreate()complètement le tir, essayez peut-être de vérifier le Bundle savedInstanceStatepassage dans l'événement pour voir s'il est nul ou non.

Par exemple, si j'ai une logique qui doit être exécutée lorsque le Activityest vraiment créé, pas à chaque changement d'orientation, je n'exécute cette logique onCreate()que si le savedInstanceStateest nul.

Sinon, je veux toujours que la mise en page soit redessinée correctement pour l'orientation.

public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_game_list);

        if(savedInstanceState == null){
            setupCloudMessaging();
        }
}

Je ne sais pas si c'est la réponse ultime, mais cela fonctionne pour moi.

nébuleuses
la source
6
et où êtes-vous en train de sauver l'état?
Ewoks
5
cela semble fonctionner pour moi et cela semble de loin la méthode la plus simple. je remarque que vous n'avez obtenu que 4 ups (5 y compris le mien) contre 373 pour l'idée de sous-classer l'application, ce qui me semble beaucoup plus compliqué. y a-t-il un inconvénient à cette méthode?
steveh
4
Cette solution a bien fonctionné pour moi. J'ai pu Intent serverintent = new Intent(MainActivity.this, MessageListener.class);et startService(serverintent);créer un serverSocket = new ServerSocket(0xcff2);et Socket client = serverSocket.accept();avec un BufferedReader(new InputStreamReader(client.getInputStream()));et je pouvais faire pivoter mon Android et garder la connexion client / serveur active, tout en faisant tourner l'interface graphique. Selon le manuel, saveInstanceState est initialisé lorsque la dernière activité est arrêtée.
Fred F
3
Je ne comprends pas, quel est le problème? Cela fonctionne très bien et avec beaucoup moins de complexité que toutes les autres solutions.
RTF
3
C'est la bonne façon de le faire dans Android. Les autres façons de capturer une rotation avec configChanges et tout ce qui est encombrant, complexe et inutile.
LukeWaggoner
99

ce que j'ai fait...

dans le manifeste, à la section des activités, a ajouté:

android:configChanges="keyboardHidden|orientation"

dans le code de l'activité, implémenté:

//used in onCreate() and onConfigurationChanged() to set up the UI elements
public void InitializeUI()
{
    //get views from ID's
    this.textViewHeaderMainMessage = (TextView) this.findViewById(R.id.TextViewHeaderMainMessage);

    //etc... hook up click listeners, whatever you need from the Views
}

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

    InitializeUI();
}

//this is called when the screen rotates.
// (onCreate is no longer called when screen rotates due to manifest, see: android:configChanges)
@Override
public void onConfigurationChanged(Configuration newConfig)
{
    super.onConfigurationChanged(newConfig);
    setContentView(R.layout.main);

    InitializeUI();
}
Quelqu'un quelque part
la source
3
pour clarifier: avec mon implémentation vous pouvez maintenant avoir une initialisation variable dans onCreate () et onConfigurationChanged () sera simplement appelé pour la rotation de l'écran. Vos variables sont maintenant isolées des rotations d'écran ;-) nice and ez
Someone Somewhere
2
J'ai tout fait comme décrit ici, mais j'obtiens NullPointerException lorsque j'essaie d'appuyer sur un bouton après un changement d'orientation. Qu'est-ce qui ne va pas?
Finnboy11
5
gardez à l'esprit que ma réponse est vieille de 3 ans et Android ne cesse d'évoluer ... Simon - avez-vous un lien vers un exemple de code? C'est ce dont les gens ont besoin.
Someone Somewhere
3
Lors de la mise en garde contre Android: configChanges, @ SimonAndréForsberg ne fait que paraphraser les documents Android . La gestion des modifications du runtime contient des informations plus détaillées sur les alternatives (y compris un exemple de code).
Leif Arne Storset
67

Ce que vous décrivez est le comportement par défaut. Vous devez détecter et gérer ces événements vous-même en ajoutant:

android:configChanges

à votre manifeste, puis les modifications que vous souhaitez gérer. Donc, pour l'orientation, vous utiliseriez:

android:configChanges="orientation"

et pour que le clavier soit ouvert ou fermé, vous utiliseriez:

android:configChanges="keyboardHidden"

Si vous voulez gérer les deux, vous pouvez simplement les séparer avec la commande pipe comme:

android:configChanges="keyboardHidden|orientation"

Cela déclenchera la méthode onConfigurationChanged dans l'activité que vous appelez. Si vous remplacez la méthode, vous pouvez transmettre les nouvelles valeurs.

J'espère que cela t'aides.

GregD
la source
2
@GregD Je sais, c'est pourquoi le moment est venu de le mettre à jour pour refléter la situation d'aujourd'hui. Étant donné le nombre de votes positifs de cette question, il est toujours fait référence à d'autres questions sur le SO.
Simon Forsberg
48

Je viens de découvrir cette tradition:

Pour maintenir l'activité en vie grâce à un changement d'orientation et la gérer onConfigurationChanged, la documentation et l'exemple de code ci-dessus le suggèrent dans le fichier manifeste:

<activity android:name=".MyActivity"
      android:configChanges="orientation|keyboardHidden"
      android:label="@string/app_name">

qui a l'avantage supplémentaire qu'il fonctionne toujours.

Le bonus est que l'omission de keyboardHiddenmai peut sembler logique, mais cela provoque des échecs dans l'émulateur (pour Android 2.1 au moins): en spécifiant uniquement orientation, l'émulateur appellera à la fois OnCreateet onConfigurationChangedparfois, et seulement à d' OnCreateautres moments.

Je n'ai pas vu l'échec sur un appareil, mais j'ai entendu dire que l'émulateur échouait pour d'autres. Cela vaut donc la peine d'être documenté.

Liudvikas Bukys
la source
14
Attention: à partir d'Android 3.2 (API niveau 13), la "taille de l'écran" change également lorsque l'appareil bascule entre l'orientation portrait et paysage. Ainsi, si vous souhaitez empêcher les redémarrages de l'exécution en raison d'un changement d'orientation lors du développement pour l'API de niveau 13 ou supérieur: android: configChanges = "orientation | keyboardHidden | screenSize"
Geltrude
Oui, l'émulateur craint beaucoup. Vous ne pouvez pas vous y fier pour signaler avec précision les modifications de configuration.
IgorGanapolsky
Ajouter android: configChanges ne doit être utilisé qu'en dernier recours . Pensez à utiliser Fragmentset à la setRetainInstanceplace.
Simon Forsberg
38

Vous pouvez également envisager d'utiliser la méthode de la plate-forme Android pour conserver les données lors des changements d'orientation: onRetainNonConfigurationInstance()et getLastNonConfigurationInstance().

Cela vous permet de conserver les données lors des modifications de configuration, telles que les informations que vous avez pu obtenir d'un serveur ou quelque chose d'autre qui a été calculé dans onCreateou depuis, tout en permettant à Android de réorganiser votre Activityutilisation du fichier xml pour l'orientation actuellement utilisée. .

Voir ici ou ici .

Il convient de noter que ces méthodes sont désormais obsolètes (bien que toujours plus flexibles que la gestion de l'orientation, changez-vous comme le suggèrent la plupart des solutions ci-dessus) avec la recommandation que tout le monde passe à Fragmentset plutôt utilise setRetainInstance(true)sur chacune que Fragmentvous souhaitez conserver.

Jon O
la source
3
Je pense vraiment que Fragments et setRetainInstance est le meilleur moyen (et recommandé par Google) de le faire, +1 pour vous et -1 pour tous les autres. Ajouter Android: configChanges ne doit être utilisé qu'en dernier recours
Simon Forsberg
32

L'approche est utile mais incomplète lors de l'utilisation de Fragments.

Les fragments sont généralement recréés lors d'un changement de configuration. Si vous ne souhaitez pas que cela se produise, utilisez

setRetainInstance(true); dans le (s) constructeur (s) du Fragment

Cela entraînera la conservation des fragments lors du changement de configuration.

http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance(boolean)

Abdo
la source
7
D'accord. Avec la dernière API Android, il semble que les fragments soient la bonne façon de gérer cela. Je ne l'ai pas encore essayé moi-même, mais d'après ce que j'ai rassemblé en lisant cette page , vous déplacez essentiellement 99% de ce que vous avez utilisé pour implémenter dans une activité dans une sous-classe d'un fragment, puis ajoutez ce fragment à l'activité. L'activité sera toujours détruite et recréée lors de la rotation de l'écran, mais vous pouvez spécifiquement dire à Android de ne pas détruire le fragment en utilisant la setRetainInstance()méthode @Abdo mentionnée.
brianmearns
25

J'ai simplement ajouté

     android:configChanges="keyboard|keyboardHidden|orientation"

dans le fichier manifeste et n'a ajouté aucune onConfigurationChangedméthode dans mon activité.

Donc, chaque fois que le clavier glisse ou rien ne se passe .

bass.t
la source
ajouté à <application ...android:configChanges="keyboard|keyboardHidden|orientation">et cela fonctionne. Mes paramètres dans build.gradle:minSdkVersion 15, compileSdkVersion 23, buildToolsVersion "23.0.2"
Junior Mayhé
19

La onCreateméthode est toujours appelée même lorsque vous changez orientationd'Android. Donc, déplacer toutes les fonctionnalités lourdes vers cette méthode ne va pas vous aider

ganesh krishnan
la source
18

Mettez le code ci-dessous dans votre <activity>balise Manifest.xml:

android:configChanges="screenLayout|screenSize|orientation"
Vaishali Sutariya
la source
17
 onConfigurationChanged is called when the screen rotates. 
 (onCreate is no longer called when screen rotates due to manifest, see:  
 android:configChanges)

Quelle partie du manifeste dit qu'il "n'appelle pas onCreate()"?

En outre, les documents de Google disent de ne pas utiliser android:configChanges(sauf en dernier recours) .... Mais les autres méthodes , ils suggèrent tous DO utilisation android:configChanges.

D'après mon expérience, l'émulateur fait TOUJOURS appel onCreate()à la rotation.
Mais les 1-2 appareils sur lesquels j'exécute le même code ... ne le font pas. (Je ne sais pas pourquoi il y aurait une différence.)

Carol
la source
16

C'est très simple, procédez comme suit:

<activity
    android:name=".Test"
    android:configChanges="orientation|screenSize"
    android:screenOrientation="landscape" >
</activity>

Cela fonctionne pour moi:

Remarque: l' orientation dépend de votre exigence

ManiTeja
la source
15

Les modifications à apporter au manifeste Android sont les suivantes:

android:configChanges="keyboardHidden|orientation" 

Les ajouts à faire à l'intérieur de l'activité sont:

public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}
sumit pandey
la source
15

Ajoutez cette ligne à votre manifeste: -

android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"

et cet extrait de l'activité: -

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }
Parin Parikh
la source
14

Il y a plusieurs moyens de le faire:

Enregistrer l'état de l'activité

Vous pouvez enregistrer l'état de l'activité dans onSaveInstanceState.

@Override
public void onSaveInstanceState(Bundle outState) {
    /*Save your data to be restored here
    Example : outState.putLong("time_state", time); , time is a long variable*/
    super.onSaveInstanceState(outState);
}

puis utilisez le bundlepour restaurer l'état.

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

    if(savedInstanceState!= null){
       /*When rotation occurs
        Example : time = savedInstanceState.getLong("time_state", 0); */
    } else {
      //When onCreate is called for the first time
    }
}

Gérez vous-même les changements d'orientation

Une autre alternative consiste à gérer vous-même les changements d'orientation. Mais cela n'est pas considéré comme une bonne pratique.

Ajoutez-le à votre fichier manifeste.

android:configChanges="keyboardHidden|orientation"

pour Android 3.2 et versions ultérieures:

android:configChanges="keyboardHidden|orientation|screenSize"

@Override
public void onConfigurationChanged(Configuration config) {
    super.onConfigurationChanged(config);

if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        //Handle rotation from landscape to portarit mode here
    } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE){
        //Handle rotation from portrait to landscape mode here
    }
}

Restreindre la rotation

Vous pouvez également limiter votre activité en mode portrait ou paysage pour éviter la rotation.

Ajoutez ceci à la balise d'activité dans votre fichier manifeste:

        android:screenOrientation="portrait"

Ou implémentez cela par programme dans votre activité:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
Piyush
la source
11

La façon dont je l' ai trouvé pour ce faire est d' utiliser les onRestoreInstanceStateet les onSaveInstanceStateévénements pour sauver quelque chose dans le Bundle(même si vous ne avez pas besoin des variables enregistrées, il suffit de mettre quelque chose là - dedans de sorte que le Bundleest vide pas). Ensuite, sur la onCreateméthode, vérifiez si le Bundleest vide, et si c'est le cas, faites l'initialisation, sinon, faites-le.

Shaun
la source
11

Même si ce n'est pas "la manière Android", j'ai obtenu de très bons résultats en gérant moi-même les changements d'orientation et en repositionnant simplement les widgets dans une vue pour prendre en compte l'orientation modifiée. C'est plus rapide que toute autre approche, car vos vues n'ont pas besoin d'être enregistrées et restaurées. Il offre également une expérience plus transparente à l'utilisateur, car les widgets repositionnés sont exactement les mêmes widgets, juste déplacés et / ou redimensionnés. Non seulement l'état du modèle, mais également l'état de la vue, peuvent être préservés de cette manière.

RelativeLayoutpeut parfois être un bon choix pour une vue qui doit se réorienter de temps en temps. Vous venez de fournir un ensemble de paramètres de mise en page portrait et un ensemble de paramètres de mise en page paysagers, avec différentes règles de positionnement relatives sur chacun, pour chaque widget enfant. Ensuite, dans votre onConfigurationChanged()méthode, vous passez l' setLayoutParams()appel approprié à un appel sur chaque enfant. Si un contrôle enfant lui-même doit être réorienté en interne , il vous suffit d'appeler une méthode sur cet enfant pour effectuer la réorientation. Cet enfant appelle également des méthodes sur l'un de ses contrôles enfants qui nécessitent une réorientation interne, etc.

Carl
la source
J'aimerais voir un exemple de code de cela, semble génial!
Henrique de Sousa
8

Chaque fois que l'écran tourne, l'activité ouverte est terminée et onCreate () est appelé à nouveau.

1 . Vous pouvez faire une chose pour enregistrer l'état de l'activité lorsque l'écran est tourné de sorte que, vous pouvez récupérer toutes les anciennes choses lorsque onCreate () de l'activité est appelée à nouveau. Référez ce lien

2. Si vous souhaitez empêcher le redémarrage de l'activité, placez simplement les lignes suivantes dans votre fichier manifest.xml.

  <activity android:name=".Youractivity"
  android:configChanges="orientation|screenSize"/>
Mansuu ....
la source
7

vous devez utiliser la méthode onSavedInstanceState pour stocker toute la valeur de son paramètre est a qui est bundle

@Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
        outPersistentState.putBoolean("key",value);
    }

et utilise

@Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        savedInstanceState.getBoolean("key");
    } 

pour récupérer et définir la valeur pour afficher les objets, il gère les rotations de l'écran

koteswara DK
la source
Cela nécessite l'API de niveau 22.
Mohammad Afrashteh
6

Remarque: je poste cette réponse si quelqu'un à l'avenir est confronté au même problème que moi. Pour moi, la ligne suivante n'a pas été suffisante:

android:configChanges="orientation"

Lorsque j'ai fait pivoter l'écran, la méthode `onConfigurationChanged (Configuration newConfig) n'a pas été appelée.

Solution: j'ai également dû ajouter "screenSize" même si le problème était lié à l'orientation. Donc, dans le fichier AndroidManifest.xml, ajoutez ceci:

android:configChanges="keyboardHidden|orientation|screenSize"

Ensuite, implémentez la méthode onConfigurationChanged(Configuration newConfig)

iHank
la source
5

Dans la section d'activité du manifest, ajoutez:

android:configChanges="keyboardHidden|orientation"
Richard K Maleho
la source
5

Ajoutez cette ligne dans le manifeste: android:configChanges="orientation|screenSize"

Vikramsinh Gaikwad
la source
4

Les gens disent que vous devriez utiliser

android:configChanges="keyboardHidden|orientation"

Mais la meilleure et la plus professionnelle façon de gérer la rotation dans Android est d'utiliser la classe Loader. Ce n'est pas une classe célèbre (je ne sais pas pourquoi), mais c'est bien mieux que l'AsyncTask. Pour plus d'informations, vous pouvez lire les tutoriels Android trouvés dans les cours Android d'Udacity.

Bien sûr, comme autre moyen, vous pouvez stocker les valeurs ou les vues avec onSaveInstanceState et les lire avec onRestoreInstanceState. Cela dépend vraiment de vous.

Théo
la source
Ouais, ajoutons des gouttes de code supplémentaire pour avoir l'air "professionnel". Ou que diriez-vous de simplement vous en tenir à la manière rapide, facile, vraie et éprouvée de le faire avec l'attribut configurationChanges.
AndroidDev
3

Après un certain temps d'essais et d'erreurs, j'ai trouvé une solution qui correspond à mes besoins dans la plupart des situations. Voici le code:

Configuration du manifeste:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.pepperonas.myapplication">

    <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:configChanges="orientation|keyboardHidden|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

Activité principale:

import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "MainActivity";

    private Fragment mFragment;

    private int mSelected = -1;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate  " + "");

        // null check not realy needed - but just in case...
        if (savedInstanceState == null) {

            initUi();

            // get an instance of FragmentTransaction from your Activity
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

            /*IMPORTANT: Do the INITIAL(!) transaction only once!
            * If we call this everytime the layout changes orientation,
            * we will end with a messy, half-working UI.
            * */
            mFragment = FragmentOne.newInstance(mSelected = 0);
            fragmentTransaction.add(R.id.frame, mFragment);
            fragmentTransaction.commit();
        }
    }


    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.d(TAG, "onConfigurationChanged  " +
                   (newConfig.orientation
                    == Configuration.ORIENTATION_LANDSCAPE
                    ? "landscape" : "portrait"));

        initUi();

        Log.i(TAG, "onConfigurationChanged - last selected: " + mSelected);
        makeFragmentTransaction(mSelected);
    }


    /**
     * Called from {@link #onCreate} and {@link #onConfigurationChanged}
     */
    private void initUi() {
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate  instanceState == null / reinitializing..." + "");
        Button btnFragmentOne = (Button) findViewById(R.id.btn_fragment_one);
        Button btnFragmentTwo = (Button) findViewById(R.id.btn_fragment_two);
        btnFragmentOne.setOnClickListener(this);
        btnFragmentTwo.setOnClickListener(this);
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME!!!");
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME, AS WELL!!!");
    }


    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume  " + "");
    }


    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause  " + "");
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy  " + "");
    }


    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.btn_fragment_one:
                Log.d(TAG, "onClick btn_fragment_one " + "");
                makeFragmentTransaction(0);
                break;

            case R.id.btn_fragment_two:
                Log.d(TAG, "onClick btn_fragment_two " + "");
                makeFragmentTransaction(1);
                break;

            default:
                Log.d(TAG, "onClick  null - wtf?!" + "");
        }
    }


    /**
     * We replace the current Fragment with the selected one.
     * Note: It's called from {@link #onConfigurationChanged} as well.
     */
    private void makeFragmentTransaction(int selection) {

        switch (selection) {
            case 0:
                mFragment = FragmentOne.newInstance(mSelected = 0);
                break;
            case 1:
                mFragment = FragmentTwo.newInstance(mSelected = 1);
                break;
        }

        // Create new transaction
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        // Replace whatever is in the fragment_container view with this fragment,
        // and add the transaction to the back stack
        transaction.replace(R.id.frame, mFragment);

        /*This would add the Fragment to the backstack...
        * But right now we comment it out.*/
        //        transaction.addToBackStack(null);

        // Commit the transaction
        transaction.commit();
    }

}

Et échantillon de fragment:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * @author Martin Pfeffer (pepperonas)
 */
public class FragmentOne extends Fragment {

    private static final String TAG = "FragmentOne";


    public static Fragment newInstance(int i) {
        Fragment fragment = new FragmentOne();
        Bundle args = new Bundle();
        args.putInt("the_id", i);
        fragment.setArguments(args);
        return fragment;
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView  " + "");
        return inflater.inflate(R.layout.fragment_one, container, false);
    }

}

Peut être trouvé sur github .

Martin Pfeffer
la source
3

Utilisez l' orientationauditeur pour effectuer différentes tâches selon différentes orientations.

@Override
public void onConfigurationChanged(Configuration myConfig) 
{
    super.onConfigurationChanged(myConfig);
    int orient = getResources().getConfiguration().orientation; 
    switch(orient) 
    {
       case Configuration.ORIENTATION_LANDSCAPE:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                    break;
       case Configuration.ORIENTATION_PORTRAIT:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                    break;
       default:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
    }
}
Akshay Paliwal
la source
3

Mettez ce code ci-dessous dans votre Activityentrée Android Manifest.

android:configChanges="orientation"

Cela ne redémarrera pas votre activité lorsque vous changerez d'orientation.

Pratik Dasa
la source
2
@Mavamaarten Probablement parce que comme d'autres l'ont souligné, c'est une mauvaise pratique et dix autres réponses ont déjà couvert cela.
MikkoP
3

Fixez l'orientation de l'écran (paysage ou portrait) dans AndroidManifest.xml

android:screenOrientation="portrait" ou android:screenOrientation="landscape"

pour cela, votre onResume()méthode n'est pas appelée.

Brajendra Pandey
la source
5
comment diable réparer quelque chose est une réponse? Pourquoi nos appareils peuvent-ils tourner si nous verrouillons les utilisateurs qui l'utilisent?
Reinherd
3

L'un des meilleurs composants d'Android Architechure présenté par Google répondra à toutes les exigences de ViewModel.

Cela est conçu pour stocker et gérer les données liées à l'interface utilisateur de manière tout au long du cycle de vie, ce qui permettra aux données de survivre lorsque l'écran tourne

class MyViewModel : ViewModel() {

Veuillez vous référer à ceci: https://developer.android.com/topic/libraries/architecture/viewmodel

Android Geek
la source
1

Vous pouvez utiliser l'objet ViewModel dans votre activité.

Les objets ViewModel sont automatiquement conservés lors des modifications de configuration afin que les données qu'ils contiennent soient immédiatement disponibles pour la prochaine activité ou instance de fragment. Lire la suite:

https://developer.android.com/topic/libraries/architecture/viewmodel

Gregory Buiko
la source