2012-06-18 11 views
13

Ho un problema con Fragments e cambio di orientamento.I frammenti non funzionano correttamente dopo la modifica dell'orientamento

Ho un'applicazione che ha un MainActivity che gestisce la commutazione Fragments tramite una barra di azione a schede. Ecco il codice per la barra delle azioni a schede e quando è selezionata una scheda.

private class MyTabListener <T extends android.support.v4.app.Fragment> implements ActionBar.TabListener { 
    private android.support.v4.app.Fragment mFragment; 
    private final Activity mActivity; 
    private final String mTag; 
    private final Class<T> mClass; 

    public MyTabListener(SherlockFragmentActivity activity, String tag, Class<T> clz) { 
     mActivity = activity; 
     mTag = tag; 
     mClass = clz; 
    } 

    @Override 
    public void onTabSelected(Tab tab, android.support.v4.app.FragmentTransaction ft) { 
     if (mFragment == null){ // check to see if the fragment has already been initialised. If not create a new one. 
      mFragment = android.support.v4.app.Fragment.instantiate(mActivity, mClass.getName()); 
      ft.add(android.R.id.content,mFragment,mTag); 
     } else { 
      ft.attach(mFragment); // if the fragment has been initialised attach it to the current activity 
     } 
    } 

    @Override 
    public void onTabUnselected(Tab tab, android.support.v4.app.FragmentTransaction ft) { 
     if (mFragment != null){ 
      ft.detach(mFragment); // when a fragment is no longer needed, detach it from the activity but dont destroy it 
     } 
    } 

    @Override 
    public void onTabReselected(Tab tab, android.support.v4.app.FragmentTransaction ft) { 

    } 

Il modo in cui vedo è che tutto funziona correttamente quando l'applicazione viene caricata prima in modalità verticale. Quando ruoto, per qualche motivo viene aggiunta un'altra istanza di Fragment1 e quindi non viene rimossa quando viene selezionata un'altra scheda. Questo è anche il caso in cui poi ruoto di nuovo in verticale.

Ho provato a utilizzare setRetainInstance(true); nel mio Fragments ma questo non funziona.

C'è un metodo che è necessario sovrascrivere o fare qualcosa con il mio Fragments prima di ruotare?

Grazie in anticipo.

EDIT Ora ho visto che onTabSelected viene richiamato quando l'attività viene ricreata. Questa potrebbe essere la causa del mio problema con i frammenti attaccati più di una volta?

Ecco le mie attività sul metodoCreate.

super.onCreate(savedInstanceState); 

     if (savedInstanceState == null) { 
      //setContentView(R.layout.main); 

     } 
    // Create the Action Bar with tabs 
     ActionBar actionBar = getSupportActionBar(); 
     actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 
     actionBar.setDisplayShowTitleEnabled(false); 
     //create the tab for track and add it to the action bar. 
     Tab tab = actionBar.newTab() 
          .setText("Track") 
          .setTabListener(new MyTabListener<TrackingFragment>(this,"track",TrackingFragment.class)); 
     actionBar.addTab(tab); 

     //create the tab for ski tracks and add it to the action bar. 
     tab = actionBar.newTab() 
         .setText("Something Tracks") 
         .setTabListener(new MyTabListener<TrackListFragment>(this,"somethingtracks",TrackListFragment.class)); 
     actionBar.addTab(tab); 

     //create the tab for photos and add it to the action bar. 
     tab = actionBar.newTab() 
         .setText("Photos") 
         .setTabListener(new MyTabListener<PhotoFragment>(this,"photos",PhotoFragment.class)); 
     actionBar.addTab(tab); 

risposta

16

breve correzione:

Nel metodo onTabSelected, prima di utilizzare if (mFragment == null) è necessario cercare di ottenere il frammento (utilizzando mFragment = getSupportFragmentManager().findFragmentByTag(mTag)). Puoi anche impostare questo dall'esterno ma non ti vedo farlo.

Il controllo if(savedInstanceState == null) su onCreate potrebbe risolvere anche questo e lo considero un approccio migliore però! :)

+0

Se inserisco il mio codice a barre azione nel metodo onCreate, non viene creato o mostrato quando l'attività viene ricreata dopo un cambiamento di orientamento. Proverò la parte supportManager ora – StuStirling

+0

+1 ... introducendo di nascosto la risposta giusta mentre stavo modificando. :) – Barak

+0

il frammento non viene passato quando chiama setTabListener? – StuStirling

8

Sembra che non si dispone di qualcosa nel metodo onCreate avvolto in un if(savedInstanceState == null), in modo che si sta creando un altro frammento in aggiunta a quello in fase di restauro dal fascio savedInstanceState.

EDIT

Guardando più da vicino il codice, penso di essere stato sbagliato onCreate, il vostro onTabSelected dovrebbe gestirlo. Penso che il tuo if (mFragment == null) sia sempre in arrivo, perché non provi a trovare il frammento. Modificare quella sezione di codice a:

@Override 
public void onTabSelected(Tab tab, android.support.v4.app.FragmentTransaction ft) { 

    mFragment = mActivity.getSupportFragmentManager().findFragmentByTag(mTag); // add this 

    if (mFragment == null){ // check to see if the fragment has already been initialised. If not create a new one. 
     mFragment = android.support.v4.app.Fragment.instantiate(mActivity, mClass.getName()); 
     ft.add(android.R.id.content,mFragment,mTag); 
    } else { 
     ft.attach(mFragment); // if the fragment has been initialised attach it to the current activity 
    } 
} 
+0

stiamo parlando nel mio frammento o nella mia attività principale? – StuStirling

+0

rischierei di indovinare la tua attività principale. Qualunque cosa ti prepari e mostri la tua vista iniziale. – Barak

+0

Ho aggiunto il mio metodo onCreate alla mia domanda sopra – StuStirling

2

ho scoperto che setRetainInstance è in realtà ignorata e tutti i frammenti creati dal android.support.v4.app.FragmentManager sono memorizzati in onSaveInstanceState e sono ricreati in onCreate.

Per me la soluzione era quella di eliminare senza mezzi termini il frammento superfluo salvato: https://stackoverflow.com/a/13996054/341091

0

se (savedInstanceState == null) non funziona sempre. a volte savedInstanceState! = null mentre è necessario aggiungere un altro frammento a causa dell'orientamento orizzontale.

Un altro approccio è quello di verificare se fm.findFragmentById (R.id.frameLayoutLeft), non importa quale l'orientamento è, è nullo o no, in caso affermativo, di creare una nuova istanza frammento altrimenti non fa nulla. Se hai bisogno di un secondo frammento in modalità orizzontale, devi prima controllare se è orizzontale o meno, in tal caso, controlla se fm.findFragmentById (R.id.frameLayoutRight) è nullo o no. se nullo, che creare, altrimenti non fare nulla perché è già lì mantenuto dal sistema operativo Android.

1

Avevo più o meno lo stesso problema, ma le soluzioni presentate sopra non sembravano funzionare nella mia situazione. Alla fine ho trovato la seguente soluzione:

@Override 
public void onTabSelected(Tab tab, FragmentTransaction ft) { 
    if (mFragment == null) { 
     mFragment = Fragment.instantiate(mActivity, mClass.getName()); 
     ft.replace(android.R.id.content, mFragment, mTag); // Use replace iso add 
    } 
    else { 
     ft.attach(mFragment); 
    } 
} 
Problemi correlati