¿Cómo difieren las operaciones popBackStack () y replace ()?
He encontrado algún comportamiento curioso en mi aplicación al administrar Fragmentos y me preguntaba si podría ayudar a arrojar algo de luz sobre por qué sucede esto.
Tengo dos Fragmentos, los llamaremos Fragmento A y Fragmento B. El flujo general de mi aplicación es que cuando el usuario interactúa con el Fragmento A de alguna manera, el Fragmento B se muestra llamando a fragmentTransaction.replace()
(esto sucede en todos los casos). Cuando muestro Fragmento B, agrego Fragmento A a la pila trasera; Entonces, cuando el usuario pulsa el botón de retroceso en el fragmento B, el fragmento A se muestra de nuevo saliendo de la pila trasera.
- Desafío: Animación personalizada de ViewPager. Cambiar la altura de los elementos elegidos (Ver doble)
- Alinea el texto dentro de un botón en Android
- Keytool genera huella digital SHA1 en lugar de MD5?
- Android: activar un botón
- ¿Qué es Maven en Android Studio?
Eso es todo bien y bueno, pero hoy he descubierto que hay un flujo de Fragmento B que llama a fragmentTransaction.replace()
, sustituyendo Fragmento B con la misma instancia del Fragmento A que está actualmente en la pila trasera.
En sí mismo no hay nada de malo en eso, sin embargo el comportamiento extraño surge cuando vuelvo del Fragmento A al Fragmento B. Si llamé fragmentTransaction.replace()
, el método onCreate()
del Fragmento B no se llama.
Sin embargo, si desplegaba el fragmento A de la pila posterior y luego lo reemplazaba con el fragmento B, el método onCreate()
del fragmento B se disparaba. ¿Por qué es esto?
Tenga en cuenta que todas las instancias de Fragmento A y Fragmento B se crean en el momento en que se inicia su actividad de host.
Editar para aclarar. El caso en el que onCreate()
se llama segunda vez es el siguiente: Fragmento A => reemplazar con Fragmento B, añadiendo el Fragmento A a la pila posterior => pop Fragmento A usando popBackStack()
=> reemplazar el Fragmento A con el Fragmento B de nuevo .
- Inyección de dependencia de Java: Dagger 1 vs Dagger 2, que es mejor?
- Solicitud con selección automática o de usuario del certificado de cliente apropiado
- Android, subir una foto para alojar en imgur programatically
- NotifydataSetChanged en Adapter se actualizará con nuevos elementos, pero no actualizará los elementos existentes
- ¿Puede utilizar declaraciones condicionales en el caso de conmutación en Android?
- Android SDK r18 parece haber roto ORMLite
- ¿Cuál debería ser el tiempo de espera de conexión estándar y el tiempo de espera del socket en android
- DexIndexOverflowException Con la API de Google Maps
replace()
hace 2 cosas:
- Eliminar el fragmento (A) actualmente añadido del contenedor (C) que indicó
- Añadir 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, esto sería 2 pasos:
- Quitar B de C
- Añadir de A a C
Después de esto, el fragmento B se detached
, y si no guardó referencias a él, será recolectado de basura.
Para responder la primera parte de su pregunta, no hay ninguna llamada onCreate()
, porque FragmentB permaneció en estado created
. Y la respuesta a la segunda parte de la pregunta es un poco más larga.
Primero, es importante entender que en realidad no agregas Fragments
a Backstack, agregas FragmentTransactions
. Por lo tanto, cuando piensa que "reemplazar con el fragmento B, añadiendo el fragmento A a la pila trasera", que realmente añadir toda esta operación a backstack – que es la sustitución de A con B. Este reemplazo consiste en 2 acciones – eliminar A y agregar B .
A continuación, el siguiente paso es hacer estallar la transacción que contiene este reemplazo. Así que no estás haciendo estallar FragmentA, estás invirtiendo "quitar A, añadir B", que se invierte es "quitar B, añadir A".
Y entonces el paso final debe ser más claro – no hay B que FragmentManager es consciente de, por lo que cuando se agrega sustituyendo A con B en su último paso, B tiene que pasar por sus métodos de ciclo de vida temprano – 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();
Esto es quizás porque el administrador de fragmentos reutilizar la instancia de fragmento en lugar de recrearlo. Si el código dentro del fragmento B onCreate()
requiere ser ejecutado cuando se muestra el fragmento, mueva el código en otro método como onResume()
.
- Administración de conexiones SQLite en Android
- CoordinatorLayout (AppbarLayout) no dibuja barra de herramientas correctamente