Fragment d'Android créé deux fois lors d'un changement d'orientation

J'ai ce problème étrange où mon fragment de liste est créé deux fois, une fois que le super.oncreat est appelé sur l'activité parent et une fois que setContentView est appelé sur la même activité parent. C'est une application simple où j'utilise une disposition différente pour l'orientation portrait et paysage.

Voici l'activité principale:

  • Quelle est la différence entre utiliser add (). AddToBackStack (), add (). Detach () et replace (). AddToBackStack () dans FragmentTransaction?
  • Comment appeler layout xml d'un autre module
  • Changement d'orientation Android VideoView avec vidéo tamponnée
  • Impossible de rafraîchir / mettre à jour la liste dans un fragment d'un autre fragment dans ViewPager
  • YouTubePlayerSupportFragment dans une application d'une seule activité avec changement d'orientation
  • Circulaire ViewPager. Les fragments ne fonctionnent pas comme ils l'ont supposé après le premier tour
  • private HeadlinesFragment headlines; @Override public void onCreate(Bundle savedInstanceState) { Log.w("MainActivity", "Before super.onCreate: " + this.toString()); super.onCreate(savedInstanceState); Log.w("MainActivity", "Before setContentView: " + this.toString()); setContentView(R.layout.news_articles); //check to see if its portrait if (findViewById(R.id.fragment_container) != null) { if(getSupportFragmentManager().findFragmentById(R.id.fragment_container) == null) { headlines = new HeadlinesFragment(); getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, headlines).commit(); } } } 

    Voici les news_articles dans le dossier layout-land:

     <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:name="com.example.android.fragments.HeadlinesFragment" android:id="@+id/headlines_fragment" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> <fragment android:name="com.example.android.fragments.ArticleFragment" android:id="@+id/article_fragment" android:layout_weight="2" android:layout_width="0dp" android:layout_height="match_parent" /> 

    Voici les news_articles dans le dossier de mise en page (pour l'orientation portrait)

     <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent" /> 

    Voici le foyer qui a été créé deux fois

     public class HeadlinesFragment extends ListFragment { OnHeadlineSelectedListener mCallback; // The container Activity must implement this interface so the frag can deliver messages public interface OnHeadlineSelectedListener { /** Called by HeadlinesFragment when a list item is selected */ public void onArticleSelected(int position); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.w("HeadlinesFragment", "inside onCreate: " + this.toString()); // We need to use a different list item layout for devices older than Honeycomb int layout = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? android.R.layout.simple_list_item_activated_1 : android.R.layout.simple_list_item_1; // Create an array adapter for the list view, using the Ipsum headlines array setListAdapter(new ArrayAdapter<String>(getActivity(), layout, Ipsum.Headlines)); } @Override public void onStart() { super.onStart(); // When in landscape layout, set the listview to highlight the selected list item // (We do this during onStart because at the point the listview is available.) if (getFragmentManager().findFragmentById(R.id.article_fragment) != null) { getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); } } @Override public void onAttach(Activity activity) { super.onAttach(activity); // This makes sure that the container activity has implemented // the callback interface. If not, it throws an exception. try { mCallback = (OnHeadlineSelectedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnHeadlineSelectedListener"); } } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { // TODO Auto-generated method stub super.onCreateOptionsMenu(menu, inflater); } @Override public void onDestroy() { Log.w("HeadlinesFragment", "inside onDestroy: " + this.toString()); super.onDestroy(); } } 

    Voici le fragment d'article

     public class ArticleFragment extends Fragment { final static String ARG_POSITION = "position"; int mCurrentPosition = 0; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.w("ArticleFragment", "inside onCreateView: " + this.toString()); if (savedInstanceState != null) { mCurrentPosition = savedInstanceState.getInt(ARG_POSITION); } // Inflate the layout for this fragment View view = inflater.inflate(R.layout.article_view, container, false); return view; } @Override public void onStart() { super.onStart(); Bundle args = getArguments(); if (args != null) { // Set article based on argument passed in updateArticleView(args.getInt(ARG_POSITION)); } else if (mCurrentPosition != -1) { // Set article based on saved instance state defined during onCreateView updateArticleView(mCurrentPosition); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // Save the current article selection in case we need to recreate the fragment outState.putInt(ARG_POSITION, mCurrentPosition); } @Override public void onDestroy() { Log.w("ArticleFragment", "inside onDestroy: " + this.toString()); super.onDestroy(); } 

    }

    Le problème est en détail:

    1) démarrer l'application en orientation portrait 2) setContentView s'appelle et news_articles est chargé mais c'est celui avec fragment_container. 3) le foyer est créé // jusqu'à présent le comportement normal 4) changer l'orientation vers le paysage 5) la principale activité est détruite -> le foyer de tête est détruit 6) super.oncreate sur la fonctionnalité est appelée 7) Fragment de la tête est créé 8) setcontentview sur la productivité est appelé 9) Un autre foyer est créé // problème

    J'ai placé les journaux comme on peut le voir dans le code ci-dessus et voici la sortie lorsque je démarre l'application en mode portrait et que je change en paysage.

     W/MainActivity(6925): Before super.onCreate: MainActivity@41d81238 W/MainActivity(6925): Before setContentView: MainActivity@41d81238 W/HeadlinesFragment(6925): inside onCreate: HeadlinesFragment{41d8d4d8 #0 id=0x7f050001} W/MainActivity(6925): inside onDestroy: MainActivity@41d81238 W/HeadlinesFragment(6925): inside onDestroy: HeadlinesFragment{41d8d4d8 # 0id=0x7f050001} W/MainActivity(6925): Before super.onCreate: MainActivity@41ea6258 W/HeadlinesFragment(6925): inside onCreate: HeadlinesFragment{41ea7290 #0 id=0x7f050001} W/MainActivity(6925): Before setContentView: MainActivity@41ea6258 W/HeadlinesFragment(6925): inside onCreate: HeadlinesFragment{41eb1f30 #1 id=0x7f050002} W/ArticleFragment(6925): inside onCreateView: ArticleFragment{41eb5f20 #2 id=0x7f050003} 

    J'espère que j'ai été clair avec mon code et les journaux, il me semble super.concreate et setcontentview crée à la fois un foyer de titres chacun; Au moins je pense.

    Ma question est de savoir pourquoi 2 instances de fragments de titre sont créées et comment je peux éviter une telle situation.

    Merci beaucoup pour toute aide à ce sujet

    2 Solutions collect form web for “Fragment d'Android créé deux fois lors d'un changement d'orientation”

    Dans le document onCreate de votre activité, vous pouvez vérifier l'état de votre lot savedInstanceState . Si ce n'est pas nul, cela signifie qu'un changement de configuration s'est produit (dans votre cas, un changement d'orientation de l'écran) et que vous n'avez pas besoin de recréer votre Fragment .

    Une autre erreur que vous avez faite était que vous findFragmentById de récupérer votre Fragment avec findFragmentById . Au lieu de passer l'identifiant Fragment, vous lui donnez l'id de la Vue attachée au Fragment, ce qui est différent (et c'est la raison pour laquelle je devine que cela a toujours été nul).

    Une mise en œuvre correcte serait plus comme ceci (c'est votre Activity ):

      //check to see if its portrait if (findViewById(R.id.fragment_container) != null) { if(savedInstanceState == null) { headlines = new HeadlinesFragment(); getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, headlines, FRAGMENT_TAG_STRING).commit(); // Use tags, it's simpler to deal with } else { headlines = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG_STRING); } } 

    Remplacer onSavedInstanceState sans l'appeler super.

    coAndroid est un fan Android de Google, tout sur les téléphones Android, Android Wear, Android Dev et Android Games Apps.