44

stato alla ricerca di questo problema per un po 'inutilmente ora:Come determinare frammento restaurato backstack

Come determinare frammento è in fase di restauro da backstack? Sto usando la libreria di compatibilità e un ListFragment all'interno di FragmentActivity. Quando viene selezionato un elemento all'interno di ListFragment, viene avviato un nuovo frammento per sostituire ListFragment.

Ho notato che quando FragmentActivity viene messa in pausa, viene chiamato onSaveInstanceState di Fragment. Ma quando Framment viene inserito nello stack posteriore tramite FragmentTransaction, onSaveInstanceState non viene richiamato, i metodi del ciclo di vita onCreateView e onActivityCreated vengono richiamati con il bundle salvatoInstanceState.

Chiedo questo perché voglio caricare alcuni dati quando il frammento viene creato o ripristinato, ma non così quando l'utente torna via. backstack.

Ho dato un'occhiata a How to check if Fragment was restored from a backstack? ma voglio aggiungere ulteriori dettagli nella speranza che questo possa stimolare una risposta.

Edit: appena notato http://developer.android.com/reference/android/app/Fragment.html#onSaveInstanceState(android.os.Bundle) dice

Nota però: questo metodo può essere chiamato in qualsiasi momento prima OnDestroy(). Ci sono molte situazioni in cui un frammento può essere in gran parte abbattuto (come quando è collocato sullo stack posteriore senza mostrare un'interfaccia utente), ma il suo stato non verrà salvato finché l'attività proprietaria non avrà effettivamente bisogno di salvare il suo stato.

Così onSaveInstanceState è sicuramente fuori questione ...

+0

Come un piccolo aggiornamento a questa domanda, sto sospettare sempre di più è a causa di capricci della biblioteca compatibilità. Non ho ancora provato a eseguire un test case su dispositivi 3.0+ ancora, controllerò quando lo farò. – dvd

+0

perché non si effettua la chiamata al server per caricare i dati in 'onCreate()'. Forse, questo allevierà i tuoi problemi. Credo che questo particolare metodo non venga chiamato quando un frammento viene ripristinato dallo stack posteriore. – Abhijit

risposta

34

Penso che la maggior parte modo semplice è farlo per esempio in onViewCreated() metodo:

if (savedInstanceState == null && !mAlreadyLoaded) { 
    mAlreadyLoaded = true; 

    // Do this code only first time, not after rotation or reuse fragment from backstack 
} 

Perché quando androide messo frammento su backstack, esso distrugge solo la sua vista, ma non uccidono istanza stessa, quindi mAlreadyLoaded sarà ancora true quando il frammento verrà ripristinato dal backstack.

+0

Questa è la risposta corretta per determinare se l'istanza del frammento è stata ripristinata dallo stack posteriore. Ho finalmente avuto la possibilità di rivisitare questo argomento e leggere l'origine di FragmentManager nella libreria di supporto v4 versione 13. L'istanza di frammento come ATOM detta viene mantenuta quando si aggiunge allo stack posteriore. Quindi, impostare e controllare un flag in onViewCreated funziona. – dvd

+5

Funziona solo se si chiama 'setRetainInstance (true)', che non è sempre un'opzione. –

+1

@BenoitDuffez Credo sia necessario solo se si sta lavorando con un 'Fragment' il cui' FragmentTransaction' non è stato aggiunto allo stack posteriore. Se la transazione è stata aggiunta allo stack posteriore, quel 'Fragment' sarà mantenuto automaticamente (cioè il suo' onDestroy' non sarà chiamato). [** Dai documenti **] (http://developer.android.com/guide/components/fragments.html#Transactions). Se non lo aggiungi allo stack posteriore, dovrai chiamare 'setRetainInstance()' come hai detto se vuoi che non venga distrutto. –

30
getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener() {  
      public void onBackStackChanged() { 
       Log.i(TAG, "back stack changed "); 
       int backCount = getSupportFragmentManager().getBackStackEntryCount(); 
       if (backCount == 0){ 
            // block where back has been pressed. since backstack is zero. 
       } 
      } 
     }); 

uso questo addOnBackStackChangedListener.

+4

Ho appena provato questo, il problema è onBackStackChanged è chiamato dopo che i metodi del frammento del ciclo di vita sono chiamati. Quello che voglio fare è: caricare i dati quando viene creato per la prima volta il frammento, memorizzare i dati e ripristinarli quando necessario (senza ricaricare). Ciò è stato ottenuto con il caricamento/ripristino condizionale in onActivityCreated. Quando il frammento viene ripristinato tramite il popping dello stack posteriore, non ricaricare i dati. Anche se imposto un flag su onBackStackChanged, i metodi del ciclo di vita non lo vedranno. – dvd

+0

Funziona come un fascino! – portfoliobuilder

+0

question.acceptedAnswer = this; – satheeshwaran

0

In alcuni casi è possibile utilizzare il metodo isVisible per capire se viene prima visualizzato un frammento o viene ripristinato dal backstack.

8

MAGGIORE EDIT: 15 ottobre 2013

La spiegazione precedente (mantenuti al di sotto per riferimento) non riesce quando l'applicazione viene messa in secondo piano e ha riportato in primo piano.

Invece, è meglio confrontare la dimensione corrente del backstack con quella quando è stato creato il frammento & inserito nel backstack.


dare una buona occhiata alla figura 2 in http://developer.android.com/guide/components/fragments.html#Creating

cosa questa cifra ti dice è che quando un frammento viene ripristinato dal backstack, la sua onCreate() non viene chiamato, mentre la sua onCreateView() è.


Quindi, si può decidere di fare qualcosa di simile:

public class MyFragment extends Fragment { 
    int mBackStackSize = 0; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     mBackStackSize = getFragmentManager().getBackStackEntryCount(); 
    } 

    public boolean isRestoredFromBackstack() { 
     return mBackStackSize > getFragmentManager().getBackStackEntryCount(); 
    } 
} 
4

Se si è aggiunto al frammento backstack, e dopo qualche manipolazione si nasconderla usando fragmentTransaction.hide (frammento) e quindi ripristinare da backstack come fragmentTransaction.show (fragmentManager.findFragmentByTag (fragment.getName())); è possibile ignorare onHiddenChanged (booleano nascosto)

@Override 
public void onHiddenChanged(boolean hidden) { 
    // TODO Auto-generated method stub 
    super.onHiddenChanged(hidden); 
    if (!hidden) { 
     //fragment became visible 
     //your code here 
    } 
} 
+0

Questo è esattamente quello che stavo cercando. Grazie! Basta notare che dovrebbe essere 'if (! Hidden) {' – crubio

0
Fragment.getFragmentManager() == null 

prima aggiunto e dopo spuntato

12

Quando un frammento va al back-stack di onDestroyView() chiamato. Non onDestroy().

E quando viene chiamato un frammento dal back stack onCreateView(). Non onCreate().

Quindi aggiungere un boolean mIsRestoredFromBackstack a frammentarsi e seguire, come di seguito:

@Override 
public void onCreate(Bundle savedInstanceState) 
{ 
    super.onCreate(savedInstanceState); 
    mIsRestoredFromBackstack = false; 
} 

@Override 
public void onResume() 
{ 
    super.onResume(); 
    if(mIsRestoredFromBackstack) 
    { 
     // The fragment restored from backstack, do some work here! 
    } 
} 

@Override 
public void onDestroyView() 
{ 
    super.onDestroyView(); 
    mIsRestoredFromBackstack = true; 
} 
+0

onDestroyView viene chiamato dal blocco dello schermo, quindi la mia azione viene chiamata due volte dopo essere tornata dal backstack – ldrrp

+1

Funziona. Grazie per aver risposto. –