Cómo persistir los datos de fragmentos después de las transacciones backstack?
Tengo una actividad, que contiene fragmento 'lista', que al hacer clic en uno de sus elementos se reemplazará a un fragmento de 'contenido'. Cuando el usuario usa el botón de retroceso, se trae de nuevo al fragmento 'lista'.
El problema es que el fragmento está en su estado predeterminado, no importa lo que intento persistir datos.
Hechos:
- Android: BackStack se comporta mal, si la aplicación se inició desde otra aplicación
- Botón Atrás cerrar la aplicación incluso cuando se utiliza FragmentTransaction.addToBackStack ()
- La forma correcta de manejar la navegación "Up" de acuerdo con las directrices
- Fragmento addToBackStack () y popBackStackImmediate () no funciona
- Obtener todos los fragmentos de backstack en orden
- Ambos fragmentos se crean a través de
public static TheFragment newInstance(Bundle args)
,setArguments(args)
yBundle args = getArguments()
- Ambos fragmentos están en el mismo nivel, que está directamente dentro de un
FrameLayout
de la actividad principal (es decir, no fragmentos anidados) - No quiero llamar a
setRetainInstance
, porque mi actividad es un flujo maestro / detallado, que tiene un diseño de 2 paneles en pantallas más grandes. Las tabletas de 7 "tienen 1 panel en el retrato y 2 paneles en el paisaje.Si retengo la instancia del fragmento 'list', se (pienso) fuck cosas con rotaciones de pantalla - Cuando el usuario hace clic en un elemento del fragmento 'lista', el fragmento 'contenido' se muestra a través de
FragmentTransaction#replace(int, Fragment, String)
, con el mismo ID pero una etiqueta diferente - Hice sobrescribir
onSaveInstanceState(Bundle)
, pero esto no siempre es llamado por el marco, como por el doc : "Hay muchas situaciones en las que un fragmento puede ser mayormente roto (como cuando se coloca en la pila trasera sin mostrar la interfaz de usuario) , Pero su estado no se salvará hasta que su actividad de propiedad realmente necesita salvar su estado ". - Estoy usando la biblioteca de soporte
De la viñeta 5 arriba, supongo que los dispositivos low-end que necesitan recuperar memoria después de una transacción fragmentada pueden llamar Fragment#onSaveInstanceState(Bundle)
. Sin embargo, en mis dispositivos de prueba (Galaxy Nexus y Nexus 7), el framework no llama a ese método. Así que no es una opción válida.
Entonces, ¿cómo puedo retener algunos datos de fragmentos? El paquete pasado al Fragment#onCreate
, Fragment#onActivityCreated
, etc. siempre es null
.
Por lo tanto, no puedo hacer una diferencia de un nuevo lanzamiento de fragmentos a una restauración de pila trasera.
Nota: posible pregunta relacionada / duplicada
- Cómo estallar fragmento de backstack
- ¿Cómo puedo guardar la pila trasera de la aplicación en un lote?
- Cómo quitar la entrada anterior de la pila trasera de FragmentManager?
- Reanudar la actividad en lugar de iniciar si ya existe en la pila trasera
- Android - Utilizar el dedo de izquierda a derecha para volver
- Borrar backstack y reemplazar fragmento actual con un fragmento de nivel superior
- Borrar la pila trasera cuando el objeto de la aplicación es eliminado por el sistema
- Fragmento onResume () no se llama cuando se salió de backstack
Esto no parece correcto, pero aquí es cómo terminé haciendo:
public class MyActivity extends FragmentActivity { private Bundle mMainFragmentArgs; public void saveMainFragmentState(Bundle args) { mMainFragmentArgs = args; } public Bundle getSavedMainFragmentState() { return mMainFragmentArgs; } // ... }
Y en el fragmento principal:
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 } }
¡Funciona!
- Si se retrocede desde backstack, el fragmento utiliza los parámetros guardados en
onDestroyView
- Si vuelve de otra aplicación / proceso / fuera de la memoria, el fragmento se restaura desde el
onSaveInstanceState
- Si se crea por primera vez, el fragmento utiliza los parámetros establecidos en
setArguments
Todos los eventos están cubiertos, y la información más fresca siempre se mantiene.
En realidad es más complicado, es interface
base, el oyente es un / registrado de onAttach
/ onDetach
. Pero los principios son los mismos.