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.
- Compatibilidad del edificio PreferenceFragment en Android
- ViewPager + FragmentPagerAdapter dentro de un DialogFragment obtiene "IllegalArgumentException: No se encontró ninguna vista ..."
- IllegalArgumentException: No se encontró ninguna vista para id para fragmento - ViewPager en ViewPager
- Obtención del error "La actividad Java.lang.IllegalStateException se ha destruido" al utilizar pestañas con ViewPager
- ¿Se puede usar la etiqueta de combinación con fragmentos?
¿Cuál es la forma correcta de mostrar un DialogFragment desde otro Fragmento que no sea DialogFragment.show (FragmentManager, String)?
- Actualización de fragmentos / vistas en viewpager con fragmentStatePagerAdapter
- Android: Pasar datos de fragmento hijo a fragmento padre
- Cómo actualizar fragmento anterior después de cerrar una actividad que se inició dentro de un adaptador?
- HeaderViewListAdapter se bloquea de forma aleatoria
- ¿Es este un uso correcto de Android Fragments y NavigationDrawer?
- NotSerializableException al guardar el estado de fragmento
- Acerca de Android Progress Dialog. ¿Evitar?
- Fragmentos onResume de la pila trasera
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