Fragmento recreado cada vez después del cambio de orientación, incapaz de restaurar estado

Actualización: Resulta que el problema es de otra parte. Gracias @Luksprog por señalar lo que pasé por alto.

  1. El proyecto se crea utilizando el patrón de navegación de Android Studio. El cajón se implementa en la clase NavigationDrawerFragment .
  2. El fragmento que contiene el paginador de vista se añade cuando se selecciona un elemento particular en el cajón. El código se implementa mi actividad en el hogar.
  3. Cuando gira la pantalla, se onCreate() método onCreate() de NavigationDrawerFragment , conservando el último elemento seleccionado.
  4. Y aquí es lo que salió mal – en la recreación, NavigationDrawerFragment volverá a llamar a selectItem (), lo que desencadena mi elemento de menú seleccionado controlador. Esto hace que el ListFragment restaurado por Android.

Esto se puede evitar comprobando el elemento de menú activo en mi código de controlador de selección de menú.


Quiero conservar el índice de la última página de visualización de ViewPager cuando la actividad se recrea por cualquier motivo, por ejemplo, cambio de orientación.

ViewPager está en un Fragment (denominado ListFragment ), que se adjunta a una actividad. Estoy utilizando la biblioteca compat, por lo que el fragmento es una subclase de android.support.v4.app.Fragment .

Pensé que podría ser hecho por sobreescribir el método onSaveInstanceState() y agregar la lógica apropiada en onCreate() , como metioned en el doc :

Para manejar adecuadamente un reinicio, es importante que su actividad restaure su estado anterior a través del ciclo de vida normal de la actividad, en el que Android llama aSaveInstanceState () antes de que destruya su actividad para que pueda guardar datos sobre el estado de la aplicación. A continuación, puede restaurar el estado durante onCreate () o onRestoreInstanceState ().

Pero la situación parece diferente para los fragmentos. El índice de página se puede restaurar correctamente cuando ListFragment este ListFragment a otra actividad y presiono "atrás". Sin embargo, cuando rota mi dispositivo, el índice de la página se pierde.

He añadido algunas anotaciones para ver lo que está mal. Del registro encontré que aunque onSaveInstanceState() del ListFragment (lo llamaré ListFragment A) se llama correctamente, esta clase particular del fragmento no se demuestra más en la actividad. Cuando se cambia la orientación y se recrea la actividad, Android llama a onSaveInstanceState() seguido de onDetach() para separar este fragmento. Entonces Android crea una nueva instancia de ListFragment (lo llamaré ListFragment B) y lo adjuntará a la nueva actividad girada. Este ListFragment B tiene un empty savedInstanceState pasado al constructor, y así se pierde el índice de la última página (y cualquier configuración en savedInstanceState del fragmento A).

De hecho, una nueva instancia de ListFragment se creará cada vez que se produzca una rotación de pantalla, pero parece que los antiguos no se destruirán. Veo los registros como a continuación cuando giro el dispositivo:

 D/ListFragment﹕ [1110257048] onSaveInstanceState() called, storing last page index 3 D/ListFragment﹕ [1109835992] onSaveInstanceState() called, storing last page index 0 D/ListFragment﹕ [1108826176] onSaveInstanceState() called, storing last page index 0 D/ListFragment﹕ [1108083096] onSaveInstanceState() called, storing last page index 0 D/ListFragment﹕ [1106541040] onSaveInstanceState() called, storing last page index 0 D/ListFragment﹕ [1108316656] onSaveInstanceState() called, storing last page index 0 D/ListFragment﹕ [1109134136] onSaveInstanceState() called, storing last page index 0 D/ListFragment﹕ [1108630992] onSaveInstanceState() called, storing last page index 0 D/ListFragment﹕ [1108592888] onSaveInstanceState() called, storing last page index 0 D/ListFragment﹕ [1109729064] onSaveInstanceState() called, storing last page index 0 D/ListFragment﹕ [1110257048] onDestroy() D/ListFragment﹕ [1110257048] onDetach() D/ListFragment﹕ [1109835992] onDestroy() D/ListFragment﹕ [1109835992] onDetach() D/ListFragment﹕ [1108826176] onDestroy() D/ListFragment﹕ [1108826176] onDetach() D/ListFragment﹕ [1108083096] onDestroy() D/ListFragment﹕ [1108083096] onDetach() D/ListFragment﹕ [1106541040] onDestroy() D/ListFragment﹕ [1106541040] onDetach() D/ListFragment﹕ [1108316656] onDestroy() D/ListFragment﹕ [1108316656] onDetach() D/ListFragment﹕ [1109134136] onDestroy() D/ListFragment﹕ [1109134136] onDetach() D/ListFragment﹕ [1108630992] onDestroy() D/ListFragment﹕ [1108630992] onDetach() D/ListFragment﹕ [1108592888] onDestroy() D/ListFragment﹕ [1108592888] onDetach() D/ListFragment﹕ [1109729064] onDestroy() D/ListFragment﹕ [1109729064] onDetach() D/ListFragment﹕ [1110903656] onAttach() D/ListFragment﹕ [1110903656] onCreate() D/ListFragment﹕ [1110903656] savedInstanceState is not NULL. D/ListFragment﹕ [1110903656] Retrieving last page index 3 D/ListFragment﹕ [1110905248] onAttach() D/ListFragment﹕ [1110905248] onCreate() D/ListFragment﹕ [1110905248] savedInstanceState is not NULL. D/ListFragment﹕ [1110905248] Retrieving last page index 0 D/ListFragment﹕ [1110906440] onAttach() D/ListFragment﹕ [1110906440] onCreate() D/ListFragment﹕ [1110906440] savedInstanceState is not NULL. D/ListFragment﹕ [1110906440] Retrieving last page index 0 D/ListFragment﹕ [1110907632] onAttach() D/ListFragment﹕ [1110907632] onCreate() D/ListFragment﹕ [1110907632] savedInstanceState is not NULL. D/ListFragment﹕ [1110907632] Retrieving last page index 0 D/ListFragment﹕ [1110908824] onAttach() D/ListFragment﹕ [1110908824] onCreate() D/ListFragment﹕ [1110908824] savedInstanceState is not NULL. D/ListFragment﹕ [1110908824] Retrieving last page index 0 D/ListFragment﹕ [1110910016] onAttach() D/ListFragment﹕ [1110910016] onCreate() D/ListFragment﹕ [1110910016] savedInstanceState is not NULL. D/ListFragment﹕ [1110910016] Retrieving last page index 0 D/ListFragment﹕ [1110911208] onAttach() D/ListFragment﹕ [1110911208] onCreate() D/ListFragment﹕ [1110911208] savedInstanceState is not NULL. D/ListFragment﹕ [1110911208] Retrieving last page index 0 D/ListFragment﹕ [1110912400] onAttach() D/ListFragment﹕ [1110912400] onCreate() D/ListFragment﹕ [1110912400] savedInstanceState is not NULL. D/ListFragment﹕ [1110912400] Retrieving last page index 0 D/ListFragment﹕ [1110913592] onAttach() D/ListFragment﹕ [1110913592] onCreate() D/ListFragment﹕ [1110913592] savedInstanceState is not NULL. D/ListFragment﹕ [1110913592] Retrieving last page index 0 D/ListFragment﹕ [1110914784] onAttach() D/ListFragment﹕ [1110914784] onCreate() D/ListFragment﹕ [1110914784] savedInstanceState is not NULL. D/ListFragment﹕ [1110914784] Retrieving last page index 0 D/HomeActivity﹕ fragment updated D/ListFragment﹕ [1110914784] onCreateView() D/ListFragment﹕ [1111031048] onAttach() D/HomeActivity﹕ Fragment attached. D/ListFragment﹕ [1111031048] onCreate() D/ListFragment﹕ [1111031048] savedInstanceState is NULL. D/ListFragment﹕ [1111031048] onCreateView() D/ListFragment﹕ [1111031048] onResume(), restoring page index 0 

Este es el registro después de girar la pantalla durante unas 10 veces. El número en la etiqueta es el hashCode() las clases. Por encima de las líneas muestra que onSaveInstanceState() y onCreate() de los fragmentos creados anteriormente aún se llaman incluso después de que son reemplazados por la última (1111031048).

Tenga en cuenta que no he llamado setRetainInstance() en la clase de fragmento. De hecho, he intentado setRetainInstance(false) y setRetainInstance(true) pero no cambia nada.

¿Hice algo mal aquí? Puedo entender que ListFragment necesita ser recreado, pero ¿ savedInstanceState qué savedInstanceState es nulo? Y si este es el comportamiento esperado, ¿cuál es la manera correcta de resolver mi necesidad, es decir, mantener el índice de la página cuando cambia la configuración?

Debería ser posible hacer que el índice de la página sea una variable de clase estática, pero no estoy seguro de si en realidad está resolviendo el problema, o simplemente escondiéndolo (porque huelo en el registro anterior).

Aunque la respuesta ya ha sido aceptada, permítanme aclarar esto más: el "problema" está en la plantilla de Android Studio. El problema, como señaló Edmund, está en el Cajón de Navegación llamando al menú cuando se recrea, por lo que volver a llamar al Fragmento. Para solucionar esto, hice esta ligera modificación en el archivo NavigationDrawerFragment.java propuesto por Android Studio. Original:

  @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Read in the flag indicating whether or not the user has demonstrated awareness of the // drawer. See PREF_USER_LEARNED_DRAWER for details. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity()); mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false); if (savedInstanceState != null) { mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION); mFromSavedInstanceState = true; } // Select either the default item (0) or the last selected item. selectItem(mCurrentSelectedPosition); } 

Uno nuevo:

  @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Read in the flag indicating whether or not the user has demonstrated awareness of the // drawer. See PREF_USER_LEARNED_DRAWER for details. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity()); mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false); if (savedInstanceState != null) { mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION); mFromSavedInstanceState = true; } else { // Select either the default item (0) or the last selected item. selectItem(mCurrentSelectedPosition); } } 

Acabo de perder medio día de producción para entender esto. Espero que pueda ayudar a alguien más.

Como actualizado en la pregunta, esto se resuelve y gracias de nuevo a @Luksprog por señalar lo que pasé por alto.

El comportamiento de Fragment realmente se alinea con las clases de Activity .

Esta es la causa de mi problema:

  • El proyecto se crea utilizando el patrón de cajón de navegación proporcionado por el asistente de "Crear proyecto" de Android Studio. El cajón se implementa en la clase NavigationDrawerFragment .
  • El fragmento que contiene el paginador de vista se añade cuando se selecciona un elemento particular en el cajón. El código se implementa mi actividad en el hogar.
  • Cuando gira la pantalla, se onCreate() método onCreate() de NavigationDrawerFragment , conservando el último elemento seleccionado.
  • Y aquí es lo que salió mal – en la recreación, NavigationDrawerFragment volverá a llamar a selectItem() , lo que desencadena mi elemento de menú seleccionado controlador. Esto hace que el ListFragment sea ​​reemplazado.

Esto puede evitarse comprobando el elemento de menú activo en mi código de controlador de selección de menú o desactivando esa llamada selectItem() .

Trate de usar onCreateView() aquí en lugar de onCreate() , que es específico de Fragmentos y podría hacer una diferencia.

onSaveInstanceState() para almacenar su estado y recuperarlo en onCreateView() usando savedInstanceState.get*() . Así es como lo hacemos en nuestras aplicaciones, y debería funcionar. Como @Ari mencionado, asegúrese de llamar a super.onSaveInstanceState(outState) .

 class MyFragment extends ListFragment { @Override public void onSaveInstanceState(Bundle outState) { outState.putString(ARG_PAGE, page); super.onSaveInstanceState(outState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if(savedInstanceState != null){ if(savedInstanceState.containsKey(ARG_PAGE)){ page = savedInstanceState.getInteger(ARG_PAGE); } } } } 

En AndroidManifest.xml agregar

 <activity android:name=".MainActivity" android:configChanges="orientation|screenSize"> </activity> 
  • ActionBar-PullToRefresh con ListView y Fragmento
  • Fragmentar o no fragmentos - Fragmentos anidados contra actividades. ¿Por qué debo usar más de una actividad?
  • ViewPager dentro de fragmento, cómo conservar el estado?
  • Comunicación entre Fragmentos en ViewPager
  • ¿Cómo crearías una vista de popover en Android, como Facebook Comments?
  • Drop Down Panning Android Fragmento de transición
  • Recycler View con GridLayoutManager horizontal El desplazamiento no funciona
  • Java.lang.IllegalStateException: No se puede realizar esta acción después de onSaveInstanceState, FragmentTabHost
  • ¿Cómo probar si una vista fragmentada es visible para el usuario?
  • Extendiendo fragmentos con listactivity
  • Cómo obtener el fragmento seleccionado
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.