2013-06-22 9 views
8

Ho un'attività, che contiene 'lista' di frammenti, che dopo aver fatto clic su uno dei suoi elementi si sostituirà a un frammento di 'contenuto'. Quando l'utente usa il pulsante Indietro, viene nuovamente inserito nel frammento "elenco".
Il problema è che il frammento è nel suo stato predefinito, non importa cosa cerco di mantenere i dati.Come mantenere i dati dei frammenti dopo le transazioni backstack?

fatti:

  1. entrambi i frammenti vengono creati attraverso public static TheFragment newInstance(Bundle args), setArguments(args) e Bundle args = getArguments()
  2. entrambi i frammenti sono sullo stesso livello, che è direttamente all'interno di un FrameLayout dall'attività principale (cioè, non frammenti annidati
  3. Non voglio chiamare setRetainInstance, perché la mia attività è un flusso principale/dettaglio, che ha un layout a 2 riquadri su schermi più grandi. Le tavolette da 7 "hanno 1 riquadro in verticale e 2 riquadri in orizzontale Se conservo l'istanza del frammento 'elenco', sarà (penso) scopare con rotazioni dello schermo
  4. quando gli utenti fanno clic su un elemento nella 'lista' frammento, il frammento di 'contenuto' è visualizzato attraverso FragmentTransaction#replace(int, Fragment, String), con lo stesso ID, ma un tag diverso
  5. ho fatto l'override onSaveInstanceState(Bundle), ma questo non è sempre chiamato dal framework, come per the doc: "ci sono molte situazioni in cui un frammento può essere in gran parte abbattuto (come quando è collocato sullo stack posteriore senza visualizzazione dell'interfaccia utente), ma il suo stato non verrà salvato finché l'attività proprietaria non avrà effettivamente bisogno di salvare il suo stato. "
  6. Sto utilizzando la libreria di supporto

Da sopra il punto 5, immagino che i dispositivi di fascia bassa che hanno bisogno di recuperare la memoria dopo una transazione frammento può chiamare Fragment#onSaveInstanceState(Bundle). Tuttavia, sui miei dispositivi di test (Galaxy Nexus e Nexus 7), il framework non chiama questo metodo. Quindi non è un'opzione valida.

Quindi, come posso conservare alcuni dati di frammento? il pacchetto passato a Fragment#onCreate, Fragment#onActivityCreated, ecc. è sempre null.

Quindi, non posso fare la differenza da un lancio del nuovo frammento a un ripristino dello stack posteriore.

Nota: possibile related/duplicate question

+0

Al momento l'unica opzione disponibile è: 'isFromBackStack = getActivity(). GetSupportFragmentManager(). GetBackStackEntryCount()> 0'. Mi piacerebbe avere qualcosa di più pulito, mi sembra un trucco. Inoltre, non ottengo un 'Bundle' dall'istanza del frammento precedente. –

risposta

8

Questo non mi sembra giusto, ma ecco come ho finito per fare:

public class MyActivity extends FragmentActivity { 
    private Bundle mMainFragmentArgs; 

    public void saveMainFragmentState(Bundle args) { 
     mMainFragmentArgs = args; 
    } 

    public Bundle getSavedMainFragmentState() { 
     return mMainFragmentArgs; 
    } 

    // ... 
} 

E nel frammento principale:

public class MainFragment extends Fragment { 
    @Override 
    public void onActivityCreated(final Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     Bundle args = ((MyActivity) getActivity()).getSavedMainFragmentState(); 

     if (args != null) { 
      // Restore from backstack 
     } else if (savedInstanceState != null) { 
      // Restore from saved instance state 
     } else { 
      // Create from fragment arguments 
      args = getArguments(); 
     } 

     // ... 
    } 

    // ... 

    @Override 
    public void onDestroyView() { 
     super.onDestroyView(); 
     Bundle args = new Bundle(); 
     saveInstance(args); 
     ((MyActivity) getActivity()).saveMainFragmentState(args); 
    } 

    @Override 
    public void onSaveInstanceState(Bundle outState) { 
     super.onSaveInstanceState(outState); 
     saveInstance(outState); 
    } 

    private void saveInstance(Bundle data) { 
     // put data into bundle 
    } 
} 

Funziona!

  • se di ritorno da backstack, il frammento utilizza i parametri salvati nel onDestroyView
  • se di ritorno da un'altra app/processo/la memoria, il frammento viene ripristinato dal onSaveInstanceState
  • se creato per la prima volta , il frammento utilizza i parametri impostati in setArguments

Tutti gli eventi sono coperti e le informazioni più recenti vengono sempre mantenute.

In realtà è più complicato, è interface -based, il listener è un/registered da onAttach/onDetach. Ma i principi sono gli stessi.

+0

Wow. Sto solo imparando Android, quindi ho il sospetto che mi manchi qualcosa. Forse dovrei leggere un libro. Non sono riuscito a far sopravvivere i dati per tutta la durata del mio frammento. Ma questo è il trucco. Grazie – terary

+1

Invece di salvare lo stato in onDestroyView per il caso backstack puoi usare FragmentManager's saveFragmentInstanceState() prima di rimuoverlo/sostituirlo. Ciò chiamerà onSaveInstanceState(). Ciò consente di mantenere il codice di persistenza dello stato in una volta. –

+0

Ho un approccio simile a questo in cui ho bisogno di salvare la lista che è stata precedentemente caricata quando il 'frammento' viene sostituito. Sai se questo potrebbe causare problemi di memoria? – jlively

Problemi correlati