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.
- El proyecto se crea utilizando el patrón de navegación 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étodoonCreate()
deNavigationDrawerFragment
, 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 restaurado por Android.
Esto se puede evitar comprobando el elemento de menú activo en mi código de controlador de selección de menú.
- Vertical TextView con Ellipsize y todas las demás funciones predeterminadas de TextView
- Mostrar ProgressDialog en la clase Fragmento
- fragmento parcial android -> deslizar para ver fragmento completo
- Estado del fragmento del cajón de navegación de Android
- Problemas con fragmentos de Android
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).
- Cómo poner Google Maps V2 en un fragmento con ViewPager
- Cómo obtener fragmentos existentes cuando se utiliza FragmentPagerAdapter
- Cajón de navegación - Desactivar clic en los elementos detrás del cajón
- Ponga a la derecha el indicador de un ExpandableListView en Android
- Cambiar el diseño del fragmento en el cambio de orientación
- Puntero nulo en la vista inflada al cargar por segunda vez un fragmento de mapa de google
- fragment.onCreateView provoca una excepción de puntero nulo
- Android: onCreate no se ejecuta en una FragmentActivity cuando su XML correspondiente está inflada?
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étodoonCreate()
deNavigationDrawerFragment
, conservando el último elemento seleccionado. - Y aquí es lo que salió mal – en la recreación,
NavigationDrawerFragment
volverá a llamar aselectItem()
, lo que desencadena mi elemento de menú seleccionado controlador. Esto hace que elListFragment
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>
- Importar proyecto android en ADT Eclipse de github
- Al inflar un layout xml dinámicamente varias veces, ¿cómo puedo diferenciar o identificar los widgets Button?