46 votes

onCreate() et onCreateView() invoquent beaucoup plus que nécessaire (Fragments)

Quelqu'un peut-il expliquer pourquoi le onCreate() y onCreateView() sont invoqués tant de fois, ce qui s'incrémente à chaque changement d'orientation ?

Voici une application très simple qui consiste en une Activity composé de deux Fragments . Le deuxième Fragment charges dynamiquement . Si vous définissez ces deux Fragments en main.xml il n'y aurait pas un tel comportement.

Voici main.xml :

       <fragment class="ets.saeref.Left"
        android:id="@+id/left_frag"
        android:layout_weight="70"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

     <FrameLayout android:id="@+id/right_frag" 
        android:layout_weight="30"
        android:layout_width="match_parent" 
        android:layout_height="match_parent"/>

</LinearLayout>

Voici le fragment gauche :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent" android:background="#000000">
    <Button android:text="Landscape" android:id="@+id/button1"
        android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>

</LinearLayout>

Voici le bon fragment :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent" android:background="#ffffff">
    <Button android:text="Landscape" android:id="@+id/button1"
        android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>

</LinearLayout>

Classe gauche :

public class Left extends Fragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i("Left", "onCreate()");
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        Log.i("Left", "onCreateView()");
        return inflater.inflate(R.layout.left, container, false);
    }
}

Classe droite :

public class Right extends Fragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i("Right", "onCreate()");
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        Log.i("Right", "onCreateView()");
        return inflater.inflate(R.layout.right, container, false);
    }
}

Classe principale :

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

        Fragment fg = new Right();
        getFragmentManager().beginTransaction().add(R.id.right_frag, fg)
            .commit();
        Log.i("Main", "onCreate()");
    }
}

Log après plusieurs changements d'orientation :

08-28 21:47:38.220: INFO/Main(1099): onCreate()
08-28 21:47:38.220: INFO/Right(1099): onCreateView()
08-28 21:47:38.220: INFO/Right(1099): onCreateView()
08-28 21:47:38.220: INFO/Right(1099): onCreateView()
08-28 21:47:38.220: INFO/Right(1099): onCreate()
08-28 21:47:38.220: INFO/Right(1099): onCreateView()
08-28 21:47:41.110: INFO/ActivityManager(142): Config changed: {1.0 0mcc0mnc en_US sw800dp w1280dp h752dp xlrg land finger -keyb/v/h -nav/h s.162}
08-28 21:47:41.140: INFO/Right(1099): onCreate()
08-28 21:47:41.140: INFO/Right(1099): onCreate()
08-28 21:47:41.140: INFO/Right(1099): onCreate()
08-28 21:47:41.140: INFO/Right(1099): onCreate()
08-28 21:47:41.170: INFO/Left(1099): onCreate()
08-28 21:47:41.170: INFO/Left(1099): onCreateView()
08-28 21:47:41.170: INFO/Main(1099): onCreate()
08-28 21:47:41.170: INFO/Right(1099): onCreateView()
08-28 21:47:41.170: INFO/Right(1099): onCreateView()
08-28 21:47:41.170: INFO/Right(1099): onCreateView()
08-28 21:47:41.170: INFO/Right(1099): onCreateView()
08-28 21:47:41.190: INFO/Right(1099): onCreate()
08-28 21:47:41.190: INFO/Right(1099): onCreateView()
08-28 21:47:45.070: INFO/ActivityManager(142): Config changed: {1.0 0mcc0mnc en_US sw800dp w800dp h1232dp xlrg port finger -keyb/v/h -nav/h s.163}
08-28 21:47:45.120: INFO/Right(1099): onCreate()
08-28 21:47:45.120: INFO/Right(1099): onCreate()
08-28 21:47:45.120: INFO/Right(1099): onCreate()
08-28 21:47:45.120: INFO/Right(1099): onCreate()
08-28 21:47:45.120: INFO/Right(1099): onCreate()
08-28 21:47:45.130: INFO/Left(1099): onCreate()
08-28 21:47:45.130: INFO/Left(1099): onCreateView()
08-28 21:47:45.130: INFO/Main(1099): onCreate()
08-28 21:47:45.130: INFO/Right(1099): onCreateView()
08-28 21:47:45.130: INFO/Right(1099): onCreateView()
08-28 21:47:45.130: INFO/Right(1099): onCreateView()
08-28 21:47:45.140: INFO/Right(1099): onCreateView()
08-28 21:47:45.140: INFO/Right(1099): onCreateView()
08-28 21:47:45.140: INFO/Right(1099): onCreate()
08-28 21:47:45.140: INFO/Right(1099): onCreateView()

48voto

Joris Wit Points 346

Je ne peux pas indiquer la documentation qui explique cela, mais la solution est de créer et d'ajouter le fragment uniquement lors du premier chargement de l'activité, comme ceci :

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    if (savedInstanceState == null) {
        Fragment fg = new Right();
        getFragmentManager().beginTransaction().add(R.id.right_frag, fg)
            .commit();
    }
    Log.i("Main", "onCreate()");
}

13voto

Ovidiu Latcu Points 20783

Oui, c'est très mal documenté. L'explication est que lorsque le Activity es restored il va "auto-magiquement" restore le site Fragments qui y ont été ajoutés, donc adding un autre Fragment dans votre Activity ajoutera essentiellement une nouvelle Fragment en plus de la précédente Fragment\s qui sont en fait restored par Android .

Ce comportement est définitivement voulu, et l'approche suggérée par @Joris Wit est la bonne.

C'est aussi très utile quand vous y pensez, parce que disons que vous avez une pile de Fragments ajoutées l'une sur l'autre, et vous pouvez y revenir en utilisant la fonction back clé. Dans le cas d'une rotation, si Android ne restaurerait pas le backstack de Fragments vous les perdrez tous, ou vous devrez mettre en place un mécanisme pour garder la trace de vos Fragment stack .

6voto

Tom Esterez Points 4923

Si vous n'utilisez pas de mises en page différentes pour les différentes orientations, je pense que vous devriez utiliser android:configChanges="orientation" dans votre manifeste. http://developer.Android.com/guide/topics/manifest/activity-element.html#config

3voto

franta kocourek Points 134

On dirait que vous avez beaucoup de fragments là-bas ! Si vous définissez le fragment dans le fichier xml, vous ne peut pas Définissez-le à nouveau dans votre code ! Il y a deux façons de définir les fragments : de façon dynamique (dans votre code) et statiquement (dans votre xml) ! Jetez un coup d'oeil ici : http://marakana.com/s/post/1250/android_fragments_tutorial

C'est un très bon tutoriel.

1voto

vitakot Points 1931

Un changement d'orientation oblige le système à suivre le processus de sauvegarde de l'état de l'instance, de mise en pause, d'arrêt, de destruction, puis de création d'une nouvelle instance de l'activité avec l'état sauvegardé. C'est la raison pour laquelle il y a tant d'appels onCreate et onCreateView.

Je ne pense pas que le if (savedInstanceState == null) dans le onCreate est une bonne idée ; le mécanisme de sauvegarde d'état ne fonctionnera pas correctement...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X