Fragmentos, DialogFragment y Rotación de Pantalla
Tengo una actividad que llama a setContentView con este XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" > <fragment android:name="org.vt.indiatab.GroupFragment" android:id="@+id/home_groups" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" /> <..some other fragments ...> </LinearLayout>
El GroupFragment extiende Fragment, y todo está bien allí. Sin embargo, muestro un DialogFragment dentro de GroupFragment. Esto muestra correctamente, sin embargo, cuando la pantalla gira, obtengo un cierre de fuerza.
- Animación de Android dejando artefactos
- ¿Cómo dejar que sólo fragmentos específicos desplazarse dentro de un ViewPager de CoordinatorLayout?
- Android: navegar hasta la actividad principal recrea la actividad principal
- Android Material diseño transiciones
- Implementación de pestañas de barras de acción con fragmentos
¿Cuál es la forma correcta de mostrar un DialogFragment desde otro Fragmento que no sea DialogFragment.show (FragmentManager, String)?
- OnItemClickListener no se puede resolver con un tipo (dentro de Fragmento)
- Android: Fragmento del ciclo de vida en la rotación de la pantalla
- FragmentTabHost no crea vista dentro de Fragmento en android
- Accidente después de agregar el elemento al menú de opciones de la barra de acción de Fragmento seguido de cambio de orientación
- Ciclo de vida de Android Fragment sobre cambios de orientación
- Fragmento de Android objeto nulo mNextAnim Crach interno
- ¿Cómo inyectar la dependencia al fragmento androide anidado?
- El fragmento del explorador de código de barras de Zxing se bloquea después de unos minutos
Hay un error en la biblioteca de compatibilidad que puede causar esto. Trate de poner esto en usted dialogfragment:
@Override public void onDestroyView() { if (getDialog() != null && getRetainInstance()) getDialog().setOnDismissListener(null); super.onDestroyView(); }
También sugiero establecer el diálogo como retenido, por lo que no se despidió después de la rotación. Poner "setRetainInstance (true)"; Por ejemplo, en el método onCreate ().
Aceptar, mientras que el método de Zsombor funciona, esto se debe a mí ser inexperto con Fragmentos y su solución causa problemas con el saveInstanceState Bundle
.
Aparentemente (al menos para un DialogFragment), debe ser una public static class
. Usted también DEBE escribir su propio static DialogFragment newInstance()
. Esto se debe a que la clase Fragment llama al método newInstance
en su método instantiate()
.
Así que en conclusión, usted DEBE escribir sus DialogFragments así:
public static class MyDialogFragment extends DialogFragment { static MyDialogFragment newInstance() { MyDialogFragment d = new MyDialogFragment(); return d; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { ... } }
Y muéstrales con:
private void showMyDialog() { MyDialogFragment d = MyDialogFragment.newInstance(); d.show(getFragmentManager(), "dialog"); }
Esto puede ser exclusivo de la biblioteca ActionBarSherlock, pero las muestras oficiales en la documentación del SDK utilizan este paradigma también.
Para superar el Bundle
siempre siendo nulo, lo onSaveInstanceState
en un campo estático en onSaveInstanceState
. Es un olor a código, pero la única solución que encontré para restaurar el diálogo y guardar el estado.
La referencia del Bundle debe onDestroy
en onDestroy
.
@Override public void onCreate(Bundle savedInstanceState) { if (savedInstanceState == null) savedInstanceState = HackishSavedState.savedInstanceState; setRetainInstance(true); } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { if (savedInstanceState == null) savedInstanceState = HackishSavedState.savedInstanceState; ... } @Override public void onDestroyView() // necessary for restoring the dialog { if (getDialog() != null && getRetainInstance()) getDialog().setOnDismissListener(null); super.onDestroyView(); } @Override public void onSaveInstanceState(Bundle outState) { ... HackishSavedState.savedInstanceState = outState; super.onSaveInstanceState(outState); } @Override public void onDestroy() { HackishSavedState.savedInstanceState = null; super.onDestroy(); } private static class HackishSavedState { static Bundle savedInstanceState; }
Utilicé una mezcla de las soluciones presentadas y añadí una cosa más. Esta es mi solución final:
Utilicé setRetainInstance (true) en el onCreateDialog; Utilicé esto:
public void onDestroyView() { if (getDialog() != null && getRetainInstance()) getDialog().setDismissMessage(null); super.onDestroyView(); }
Y como una solución de la savedInstanceState no funciona, he creado una clase privada llamada StateHolder (de la misma manera que un titular es crear para una listView):
private class StateHolder { String name; String quantity; }
Yo salvo el estado de esta manera:
@Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); stateHolder = new StateHolder(); stateHolder.name = actvProductName.getText().toString(); stateHolder.quantity = etProductQuantity.getText().toString(); }
En el método onDismiss establecí el stateHolder de nuevo a null. Cuando se crea el diálogo, verifica si el stateHolder no es nulo para recuperar el estado o simplemente inicializar todo normalmente.
He resuelto este problema con las respuestas de @ ZsomborErdődy-Nagy y @AndyDennie. Debes subclase esta clase y en tu fragmento padre llamar a setRetainInstance(true)
, y dialogFragment.show(getFragmentManager(), "Dialog");
public class AbstractDialogFragment extends DialogFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); } @Override public void onDestroyView() { if (getDialog() != null && getRetainInstance()) getDialog().setDismissMessage(null); super.onDestroyView(); } }
Tuve un problema similar, sin embargo ninguno de los anteriores funcionó para mí. Al final necesitaba crear el fragmento en código en vez de en el diseño XML.
Consulte: Sustitución de fragmentos y cambio de orientación
Me encontré con esto en mi proyecto y ninguna de las soluciones anteriores ayudó.
Si la excepción parece algo así como
java.lang.RuntimeException: Unable to start activity ComponentInfo{ ... Caused by: java.lang.IllegalStateException: Fragment.... did not create a view.
Es causado por un problema con un identificador de contenedor que se utiliza después de la rotación. Vea este boleto para más detalles:
https://code.google.com/p/android/issues/detail?id=18529
Básicamente, puede prevenir el bloqueo asegurándose de que todos los fragmentos xml tengan una etiqueta definida en el diseño. Esto evita que se produzca la condición de retroceso si gira cuando un fragmento es visible.
En mi caso pude aplicar esta corrección sin tener que sobrescribir onDestroyView () o setRetainInstance (true), que es la recomendación común para esta situación.
Encontré este problema y el truco de onDestroyView()
no funcionaba. Resultó que era porque estaba haciendo una creación bastante intensa de diálogo en onCreate()
. Esto incluyó guardar una referencia al AlertDialog
, que luego volvería en onCreateDialog()
.
Cuando moví todo este código a onCreateDialog()
y dejé de retener una referencia al diálogo, empezó a funcionar de nuevo. Espero que estaba violando uno de los invariants que DialogFragment
tiene sobre la gestión de su diálogo.
En onCreate()
llame a setRetainInstance(true)
y luego incluya esto:
@Override public void onDestroyView() { if (getDialog() != null && getRetainInstance()) { getDialog().setOnDismissMessage(null); } super.onDestroyView(); }
Cuando llama a setRetainInstance(true)
en onCreate (), onCreate () ya no se llamará a través de los cambios de orientación, pero onCreateView () seguirá siendo llamado.
Así que aún puede guardar el estado en su paquete en onSaveInstanceState()
y luego recuperarlo en onCreateView()
:
@Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("myInt", myInt); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.my_layout, container); if (savedInstanceState != null) { myInt = savedInstanceState.getInt("myInt"); } ... return view; }
- Mostrar un cuadro de diálogo de alerta en el receptor de difusión después de un reinicio del sistema
- HLS (http streaming en vivo) en Android 3.0 y buscando