Utilisation du package de compatibilité pour cibler 2.2 à l'aide de fragments.
Après avoir recodé une activité pour utiliser des fragments dans une application, je n'ai pas pu faire fonctionner les changements d'orientation / gestion de l'état, j'ai donc créé une petite application de test avec un seul FragmentActivity et un seul Fragment.
Les journaux des changements d'orientation sont étranges, avec plusieurs appels aux fragments OnCreateView.
Il me manque évidemment quelque chose - comme détacher le fragment et le rattacher plutôt que de créer une nouvelle instance, mais je ne vois aucune documentation qui indiquerait où je vais mal.
Quelqu'un peut-il faire la lumière sur ce que je fais de mal ici, s'il vous plaît. Merci
Le journal est le suivant après les changements d'orientation.
Initial creation
12-04 11:57:15.808: D/FragmentTest.FragmentTestActivity(3143): onCreate
12-04 11:57:15.945: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:57:16.081: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null
Orientation Change 1
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): onSaveInstanceState
12-04 11:57:39.031: D/FragmentTest.FragmentTestActivity(3143): onCreate
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:57:39.167: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null
Orientation Change 2
12-04 11:58:32.162: D/FragmentTest.FragmentOne(3143): onSaveInstanceState
12-04 11:58:32.162: D/FragmentTest.FragmentOne(3143): onSaveInstanceState
12-04 11:58:32.361: D/FragmentTest.FragmentTestActivity(3143): onCreate
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null
12-04 11:58:32.498: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:58:32.498: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null
Activité principale (FragmentActivity)
public class FragmentTestActivity extends FragmentActivity {
/** Called when the activity is first created. */
private static final String TAG = "FragmentTest.FragmentTestActivity";
FragmentManager mFragmentManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d(TAG, "onCreate");
mFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
FragmentOne fragment = new FragmentOne();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
}
Et le fragment
public class FragmentOne extends Fragment {
private static final String TAG = "FragmentTest.FragmentOne";
EditText mEditText;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(TAG, "OnCreateView");
View v = inflater.inflate(R.layout.fragmentonelayout, container, false);
// Retrieve the text editor, and restore the last saved state if needed.
mEditText = (EditText)v.findViewById(R.id.editText1);
if (savedInstanceState != null) {
Log.d(TAG, "OnCreateView->SavedInstanceState not null");
mEditText.setText(savedInstanceState.getCharSequence("text"));
}
else {
Log.d(TAG,"OnCreateView->SavedInstanceState null");
}
return v;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d(TAG, "FragmentOne.onSaveInstanceState");
// Remember the current text, to restore if we later restart.
outState.putCharSequence("text", mEditText.getText());
}
Manifeste
<uses-sdk android:minSdkVersion="8" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:label="@string/app_name"
android:name=".activities.FragmentTestActivity"
android:configChanges="orientation">
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Réponses:
Vous superposez vos fragments les uns sur les autres.
Lorsqu'un changement de configuration se produit, l'ancien fragment s'ajoute à la nouvelle activité lorsqu'il est recréé. C'est une douleur énorme à l'arrière la plupart du temps.
Vous pouvez empêcher les erreurs de se produire en utilisant le même fragment au lieu d'en recréer un nouveau. Ajoutez simplement ce code:
Soyez averti cependant: des problèmes se produiront si vous essayez d'accéder aux vues d'activité depuis l'intérieur du fragment car les cycles de vie changeront subtilement. (Obtenir des vues d'une activité parent à partir d'un fragment n'est pas facile).
la source
"when the activity is destroyed, so are all fragments"
:? Depuis"When the screen orientation changes, the system destroys and recreates the activity [...]"
.Pour citer ce livre , "pour garantir une expérience utilisateur cohérente, Android conserve la mise en page Fragment et la pile arrière associée lorsqu'une activité est redémarrée en raison d'un changement de configuration." (p. 124)
Et la façon d'aborder cela consiste à vérifier d'abord si la pile arrière de fragments a déjà été remplie et à créer la nouvelle instance de fragment uniquement si ce n'est pas le cas:
la source
La méthode onCreate () de votre activité est appelée après le changement d'orientation comme vous l'avez vu. Par conséquent, n'exécutez pas la FragmentTransaction qui ajoute le fragment après le changement d'orientation dans votre activité.
Les fragments doivent et doivent rester inchangés.
la source
Vous pouvez
@Override
utiliser FragmentActivityonSaveInstanceState()
. Veillez à ne pas appeler lesuper.onSaveInstanceState()
dans la méthode.la source
Nous devrions toujours essayer d'éviter les exceptions nullpointer, nous devons donc d'abord vérifier dans la méthode saveinstance les informations sur le bundle. pour une brève explication pour vérifier ce lien de blog
la source
Si vous ne faites qu'un projet, le chef de projet dit que vous devez obtenir un écran de fonction de commutation, mais que vous ne voulez pas afficher une mise en page différente de charge de commutation (peut créer un système de mise en page et de port de mise en page.
Vous allez déterminer automatiquement l'état de l'écran, charger la mise en page correspondante), en raison de la nécessité de réinitialiser l'activité ou le fragment, l'expérience utilisateur n'est pas bonne, pas directement sur le commutateur d'écran, je me réfère? Url = YgNfP-vHy-Nuldi7YHTfNet3AtLdN-w__O3z1wLOnzr3wDjYo7X7PYdNyhw8R24ZE22xiKnydni7R0r35s2fOLcHOiLGYT9Qh_fjqtytJkie & wd1087008000 = fj0000800001
Le principe est que votre mise en page utilise le poids de la façon dont la mise en page de layout_weight, comme suit:
Mon approche est donc, lors du changement d'écran, de ne pas avoir besoin de charger une nouvelle mise en page du fichier de vue, de modifier la mise en page dans les pondérations dynamiques onConfigurationChanged, les étapes suivantes: 1 premier jeu: AndroidManifest.xml dans l'attribut d'activité: android: configChanges = "keyboardHidden | orientation | screenSize" Pour éviter le changement d'écran, évitez le rechargement, afin de pouvoir surveiller dans onConfigurationChanged 2 l'activité de réécriture ou le fragment dans la méthode onConfigurationChanged.
la source
Lors du changement de configuration, le framework créera une nouvelle instance du fragment pour vous et l'ajoutera à l'activité. Donc au lieu de ça:
faites ceci:
Veuillez noter que le framework ajoute une nouvelle instance de FragmentOne lors d'un changement d'orientation, sauf si vous appelez setRetainInstance (true), auquel cas il ajoutera l'ancienne instance de FragmentOne.
la source