2012-06-02 8 views
162

dire che ho un'attività che ha aggiunto frammenti di codice:programmazione tornare al frammento precedente nella backstack

private void animateToFragment(Fragment newFragment, String tag) { 
    FragmentTransaction ft = getFragmentManager().beginTransaction(); 
    ft.replace(R.id.fragment_container, newFragment, tag); 
    ft.addToBackStack(null); 
    ft.commit(); 
} 

Qual è il modo migliore per tornare al frammento precedente, che era visibile?

ho trovato Trigger back-button functionality on button click in Android ma sto pensando la simulazione di un evento chiave schiena non è il modo giusto per andare su di esso (e non riesco a farlo funzionare neanche):

dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK)); 

Calling finish() solo chiude l'attività a cui non sono interessato.

C'è un modo migliore per fare questo?

risposta

265

Guarda le getFragmentManager().popBackStack() metodi (ci sono diversi tra cui scegliere)

http://developer.android.com/reference/android/app/FragmentManager.html#popBackStack()

+71

'getFragmentManager(). PopBackStackImmediate();' ha fatto il trucco. Grazie. –

+0

Dove metterei questo metodo? Nel mio listener di schede? – rasen58

+1

senza vedere il codice, è difficile da dire ... ma dovrebbe andare nella sezione di codice che viene eseguita quando si desidera "chiudere" il frammento corrente e tornare al frammento precedente. – stuckless

105

di approfondire le altre risposte fornite, questa è la mia soluzione (collocato in un'Attività):

@Override 
public void onBackPressed(){ 
    FragmentManager fm = getFragmentManager(); 
    if (fm.getBackStackEntryCount() > 0) { 
     Log.i("MainActivity", "popping backstack"); 
     fm.popBackStack(); 
    } else { 
     Log.i("MainActivity", "nothing on backstack, calling super"); 
     super.onBackPressed(); 
    } 
} 
+5

e perché sta succedendo. Nell'esempio di frammentazione http://developer.android.com/training/basics/fragments/index.html non sono eccessivi nell'evento backback e tuttavia sono in grado di eseguire il backstack del frammento. Ho usato \t trasaction.addToBackStack (null); ma non succede nulla. Puoi spiegare perché? –

+0

@MurtazaHussain dovresti probabilmente fare una nuova domanda se vuoi aiuto con questo. È un po 'difficile vedere cosa succede senza guardare altro codice. –

+2

Nel mio caso dovevo fare 'fm.getBackStackEntryCount()> 1' per richiamare l'attività quando c'è solo il primo frammento nello stack. –

21

Quando si aggiorna/aggiungi i frammenti,

Includi il .addToBackStack().

getSupportFragmentManager().beginTransaction() 
    .add(detailFragment, "detail") // Add this transaction to the back stack (name is an optional name for this back stack state, or null). 
    .addToBackStack(null) 
    .commit(); 

Dopo di che se diamo il getFragments.popBackStackImmediate() restituisce true se aggiungiamo/aggiorniamo i frammenti, e tornare alla schermata corrente.

1

Torna al frammento precedente utilizzando il seguente codice.

if (getFragmentManager().getBackStackEntryCount() > 0) 
{ 
      getFragmentManager().popBackStack(); 
      return; 
} 
super.onBackPressed(); 
15

replace() fa 2 cose:

  1. Rimuovere frammento attualmente aggiunto (A) dal contenitore (C) hai indicato
  2. Aggiungi nuovo frammento (B) per lo stesso contenitore

Queste 2 operazioni sono ciò che viene salvato come record/transazione Backstack. Si noti che il frammento A rimane nello stato created e la sua vista viene distrutta.

Ora popBackStack() inverte l'ultima transazione che hai aggiunto a BackStack.

In questo caso, che sarebbe a 2 passi:

  1. Rimuovere B da C
  2. Aggiungi A a C

Dopo questo, frammento B diventa detached, e se non avete tenuto riferimenti ad esso, sarà garbage collection.

Per rispondere alla prima parte della domanda, non c'è la chiamata onCreate(), perché FragmentB è rimasto nello stato created. E rispondere alla seconda parte della domanda è un po 'più lungo.

Innanzitutto, è importante capire che in realtà non si aggiunge Fragments a Backstack, si aggiunge FragmentTransactions. Quindi, quando pensi di "sostituire con Frammento B, aggiungendo Frammento A allo stack posteriore", aggiungi effettivamente l'intera operazione a backstack - ovvero sostitutiva di A con B. Questa sostituzione consiste di 2 azioni - rimuovi A e aggiungi B.

Quindi, il passaggio successivo è il popping della transazione che contiene questa sostituzione. Quindi non stai scoccando FragmentA, stai invertendo "rimuovi A, aggiungi B", che invertito è "rimuovi B, aggiungi A".

E poi passo finale dovrebbe essere più chiaro - non c'è B che FragmentManager è a conoscenza, in modo che quando lo si aggiunge sostituendo A con B al vostro ultimo passo, B ha la necessità di passare attraverso i suoi primi metodi del ciclo di vita - onAttach() e onCreate().

Il seguente codice illustra cosa sta succedendo.

FragmentManager fm = getFragmentManager(); 
FragmentA fragmentA = new FragmentA(); 
FragmentB fragmentB = new FragmentB(); 

// 1. Show A 
fm.beginTransaction() 
    .add(fragmentA, R.id.container) 
    .commit(); 

// 2. Replace A with B 
// FragmentManager keeps reference to fragmentA; 
// it stays attached and created; fragmentB goes 
// through lifecycle methods onAttach(), onCreate() 
// and so on. 
fm.beginTransaction() 
    .replace(fragmentB, R.id.container) 
    .addToBackstack(null) 
    .commit(); 

// 2'. Alternative to replace() method 
fm.beginTransaction() 
    .remove(fragmentA) 
    .add(fragmentB, R.id.container) 
    .addToBackstack(null) 
    .commit(); 

// 3. Reverse (2); Result - A is visible 
// What happens: 
// 1) fragmentB is removed from container, it is detached now; 
//  FragmentManager doesn't keep reference to it anymore 
// 2) Instance of FragmentA is placed back in the container 
// Now your Backstack is empty, FragmentManager is aware only 
// of FragmentA instance 
fm.popBackStack(); 

// 4. Show B 
// Since fragmentB was detached, it goes through its early 
// lifecycle methods: onAttach() and onCreate(). 
fm.beginTransaction() 
    .replace(fragmentB, R.id.container) 
    .addToBackstack(null) 
    .commit(); 
3

Aggiungi quelle linee al tuo metodo onBackPressed(). popBackStackImmediate() metodo, per tornare al frammento precedente, se avete qualche frammento sulla pila di nuovo `

if(getFragmentManager().getBackStackEntryCount() > 0){ 
    getFragmentManager().popBackStackImmediate(); 
} 
else{ 
    super.onBackPressed(); 
} 

`

0

Questa soluzione funziona perfettamente per la parte inferiore barra di navigazione frammento based quando si desidera chiudere il app quando si preme indietro nel frammento primario.

D'altra parte quando si apre il frammento secondario (frammento in frammento) definito come "DetailedPizza" nel mio codice, si tornerà allo stato precedente del frammento primario. Saluti !

attività all'interno sulla schiena premuta messo questo:

Fragment home = getSupportFragmentManager().findFragmentByTag("DetailedPizza"); 

    if (home instanceof FragmentDetailedPizza && home.isVisible()) { 
     if (getFragmentManager().getBackStackEntryCount() != 0) { 
      getFragmentManager().popBackStack(); 
     } else { 
      super.onBackPressed(); 
     } 

    } else { 
     //Primary fragment 
     moveTaskToBack(true); 
    } 

e lanciare l'altro frammento in questo modo:

Fragment someFragment = new FragmentDetailedPizza(); 
    FragmentTransaction transaction = getFragmentManager().beginTransaction(); 
    transaction.replace(R.id.container_body, someFragment, "DetailedPizza"); 
    transaction.addToBackStack("DetailedPizza"); 
    transaction.commit(); 
1

per fare quel frammento venire di nuovo, basta aggiungere quel frammento di backstack cui si desidera per tornare indietro, ad esempio:

button.setOnClickListener(new View.OnClickListener() { 
    @Override 
    public void onClick(View v) { 
     Fragment fragment = new LoginFragment(); 
     //replacing the fragment 
     if (fragment != null) { 
      FragmentTransaction ft = ((FragmentActivity)getContext()).getSupportFragmentManager().beginTransaction(); 
      ft.replace(R.id.content_frame, fragment); 
      ft.addToBackStack("SignupFragment"); 
      ft.commit(); 
     } 
    } 
}); 

Nel caso di cui sopra, sto aprendo LoginFragment quando viene premuto Button button, in questo momento l'utente è in SignupFragment. Quindi, se si chiama addToBackStack(TAG), dove , quindi quando si preme il pulsante Indietro in LoginFragment, si torna a SignUpFragment.

Happy Coding!