2012-08-27 21 views
6

La mia applicazione Android ha un ActionBar che cambia che Fragment occupa un determinato FrameLayout. Sto cercando di utilizzare onSaveInstanceState per salvare lo stato di un frammento quando la scheda viene modificata, in modo che possa essere ripristinata in onCreateView.Scollegamento di un frammento non attivando onSaveInstanceState()

Il problema è, onSaveInstanceState non viene mai chiamato. I metodi e onCreateView vengono chiamati, ma lo Bundle fornito a onCreateView rimane nullo.

Qualcuno può spiegare a me quando onSaveInstanceState è effettivamente chiamato, come posso fare in modo che viene chiamato quando si passa le schede, o la migliore pratica per il salvataggio e il ripristino dello stato di un Fragment quando si è staccato e riattaccato?

Frammento:

@Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
     Bundle savedInstanceState) { 
    View view = inflater.inflate(R.layout.event_log, container, false); 

    // Retrieve saved state 
    if (savedInstanceState != null){ 
     System.out.println("log retrieved"); 
    } else { 
     System.out.println("log null"); 
    } 

    return view; 
} 

@Override 
public void onSaveInstanceState(Bundle outState) { 
    System.out.println("log saved"); 
    super.onSaveInstanceState(outState); 
    // more code 
} 

attività:

/** 
* Detach the current Fragment, because another one is being attached. 
*/ 
@Override 
public void onTabUnselected(Tab tab, FragmentTransaction ft) { 
    if (tab.getText().equals(getString(R.string.tab_events))){ 
     if (frEventLog != null) { 
      ft.detach(frEventLog); 
    } 
} 
+0

Possibile copia di http://stackoverflow.com/questions/8503629/fragments-onsaveinstancestate-never-called – DeeV

+0

ciò che è frEventLog? –

risposta

8

Fragment#onSaveInstanceState viene chiamato solo quando il Activity ospita il Fragment è distrutto e non v'è una possibilità che si può tornare alla stessa attività ed il il frammento viene ancora aggiunto allo FragmentManager. Il caso più comune sarebbe la rotazione dello schermo.

Penso che il tuo Fragment dovrà anche fare setRetainInstance(true) in onCreate per esempio. Non sono proprio sicuro di quel punto però.

Si dovrebbe anche vedere questo metodo essere chiamato quando si preme il pulsante home, ad esempio. Questo distruggerà l'attività ma puoi tornare ad essa usando l'elenco delle attività, per esempio.

Se si dispone solo di detach() il frammento tutto quello che devi fare per riaverlo è per chiedere il FragmentManager per esso.

Ci sono due esempi si dovrebbe avere uno sguardo a:

ActionBar FragmentTabs e TabHost FragmentTabs

L'esempio TabHost utilizza

ft.add(containerId, fragment, tag); 
// later 
fragment = mActivity.getSupportFragmentManager().findFragmentByTag(tag); 

per trovare le istanze del aggiunti in precedenza Fragment s, funziona fino a quando remove() a Fragment


Riguardo a onCreateView/onDestroyView: Viene chiamato una volta che un frammento si stacca perché la prossima volta che lo si collega deve creare un nuovo View. Notare che Fragment#onDetached() non viene chiamato quando si usa il frammento detach() perché è ancora collegato allo Activity. È solo distaccato dalla gerarchia della vista.


V'è un altro bell'esempio su come mantenere lo stato frammento/come utilizzare i frammenti di mantenere lo stato in Training Android - Caching Bitmaps.

Questo esempio non è presente una linea critica però:

public static RetainFragment findOrCreateRetainFragment(FragmentManager fm) { 
    RetainFragment fragment = (RetainFragment) fm.findFragmentByTag(TAG); 
    if (fragment == null) { 
     fragment = new RetainFragment(); 
     fm.beginTransaction().add(fragment, TAG).commit(); // << add this 
    } 
    return fragment; 
} 
+0

Grazie per la risposta. Avevo l'impressione che l'utilizzo di setRetainInstance (true) fosse piuttosto dispendioso in termini di memoria, dal momento che significherebbe archiviare le schede piuttosto che distruggerle e ricrearle, ma ci provo. Devo impossessarmi dei miei frammenti tramite FragmentManager o posso mantenere un riferimento ad essi in un campo? – Dan

+0

Non hai bisogno di alcun riferimento. FragmentManager ha riferimenti ad essi ma è possibile aggiungerne uno se non si aggiungono perdite di memoria. L'intensità della memoria dipende da quanto usi nei tuoi frammenti, che può essere vicino a 0 se lo fai correttamente – zapl

+0

Penso di averlo risolto ora con l'aiuto del tuo primo esempio. Il mio problema era in realtà che avevo del codice nel metodo onActivityCreated() di Fragment che essenzialmente lo ripristinava, poiché non mi ero reso conto che questo metodo sarebbe stato eseguito più di una volta. – Dan