Volvemos programáticamente al fragmento anterior en la backstack

Supongamos que tengo una actividad que tiene fragmentos agregados programáticamente:

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

¿Cuál es la mejor manera de volver al fragmento anterior que era visible?

Encontré la funcionalidad de botón de retroceso de Trigger al hacer clic con el botón en Android, pero estoy pensando que simular un evento de tecla de retroceso no es la manera correcta de hacerlo (y tampoco puedo hacer que funcione):

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

Calling finish() acaba de cerrar la actividad que no me interesa.

¿Hay una mejor manera de hacerlo?

Mire los getFragmentManager().popBackStack() (hay varios para elegir)

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

Para elaborar sobre las otras respuestas proporcionadas, esta es mi solución (colocada en una Actividad):

 @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(); } } 

Cuando estamos actualizando / agregamos los fragmentos,

Debería incluir el .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(); 

Después de eso, si le damos getFragments.popBackStackImmediate() devolverá true si agregamos / actualizamos los fragmentos y regresamos a la pantalla actual.

replace() hace 2 cosas:

  1. Elimine el fragmento agregado actualmente (A) del contenedor (C) que indicó
  2. Agregue un nuevo fragmento (B) al mismo contenedor

Estas 2 operaciones son lo que se guarda como un registro / transacción Backstack. Tenga en cuenta que el fragmento A permanece en estado created y su vista se destruye.

Ahora popBackStack() invierte su última transacción que ha agregado a BackStack.

En este caso, serían 2 pasos:

  1. Eliminar B de C
  2. Agregar A a C

Después de esto, el fragmento B se detached , y si no guardó referencias a él, será basura recolectada.

Para responder la primera parte de su pregunta, no hay llamada onCreate() , porque FragmentB se mantuvo en estado created . Y la respuesta a la segunda parte de la pregunta es un poco más larga.

En primer lugar, es importante comprender que en realidad no agrega Fragments a Backstack, agrega FragmentTransactions . Entonces, cuando piensas que “reemplazas con el Fragmento B, agregando el Fragmento A a la stack posterior”, en realidad agregas toda esta operación al backstack, es decir, el reemplazo de A con B. Este reemplazo consta de 2 acciones: elimina A y B agrega .

Luego, el siguiente paso es hacer estallar la transacción que contiene este reemplazo. Entonces, no estás reventando FragmentA, estás invirtiendo “remove A, add B”, que se revirtió es “remove B, add A”.

Y luego el paso final debería ser más claro: no hay ninguna B de la que FragmentManager tenga conocimiento, así que cuando la agregue reemplazando A con B en su último paso, B debe pasar por sus primeros métodos de ciclo de vida: onAttach() y onCreate() .

El siguiente código ilustra lo que está sucediendo.

 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(); 

Agregue esas líneas a su método onBackPressed (). El método popBackStackImmediate () lo llevará de vuelta al fragmento anterior si tiene algún fragmento en la stack posterior `

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

`

Volvemos programáticamente al fragmento anterior usando el siguiente código.

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

Esta solución funciona perfectamente para la navegación de fragmentos basada en la barra inferior cuando se desea cerrar la aplicación cuando se presiona la parte posterior en el fragmento principal.

Por otro lado, cuando está abriendo el fragmento secundario (fragmento en fragmento) que se define como “DetailedPizza” en mi código, devolverá el estado anterior del fragmento primario. ¡Salud!

Las actividades interiores en la parte posterior presionada ponen esto:

 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); } 

Y lanza el otro fragmento así:

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

Para hacer que ese fragmento vuelva a aparecer, simplemente agrega ese fragmento al backstack que deseas volver a presionar, por ejemplo:

 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(); } } }); 

En el caso anterior, estoy abriendo LoginFragment cuando se presiona el Button button , ahora el usuario está en SignupFragment . Entonces, si se addToBackStack(TAG) , donde TAG = "SignupFragment" , cuando se presiona el botón LoginFragment en LoginFragment , volvemos a SignUpFragment .

Feliz Codificación!