Cómo retener correctamente un DialogFragment a través de la rotación?

Tengo un FragmentActivity que recibe un DialogFragment.

El DialogFragment realizar las solicitudes de red y gestiona la autenticación de Facebook, así que necesito retenerlo durante la rotación.

He leído todas las otras preguntas relacionadas con este tema, pero ninguna de ellas ha resuelto el problema.

Estoy utilizando putFragment y getFragment para guardar la instancia Fragment y volver a obtenerla durante la recreación de la actividad.

Sin embargo, siempre obtengo una excepción de puntero nulo en la llamada a getFragment en onRestoreInstanceState. También me gustaría mantener el diálogo de ser despedido durante la rotación, pero hasta ahora no puedo ni siquiera conservar la instancia de la misma.

Cualquier idea de lo que va mal?

Esto es lo que mi código parece actualmente:

public class OKLoginActivity extends FragmentActivity implements OKLoginDialogListener { private OKLoginFragment loginDialog; private static final String TAG_LOGINFRAGMENT = "OKLoginFragment"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); FragmentManager fm = getSupportFragmentManager(); if(savedInstanceState == null) { loginDialog = new OKLoginFragment(); loginDialog.show(fm, TAG_LOGINFRAGMENT); } } @Override public void onSaveInstanceState(Bundle outState) { getSupportFragmentManager().putFragment(outState,TAG_LOGINFRAGMENT, loginDialog); } @Override public void onRestoreInstanceState(Bundle inState) { FragmentManager fm = getSupportFragmentManager(); loginDialog = (OKLoginFragment) fm.getFragment(inState, TAG_LOGINFRAGMENT); } } 

Este es el rastreo de la pila de excepciones:

 02-01 16:31:13.684: E/AndroidRuntime(9739): FATAL EXCEPTION: main 02-01 16:31:13.684: E/AndroidRuntime(9739): java.lang.RuntimeException: Unable to start activity ComponentInfo{io.openkit.example.sampleokapp/io.openkit.OKLoginActivity}: java.lang.NullPointerException 02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180) 02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230) 02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3692) 02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.ActivityThread.access$700(ActivityThread.java:141) 02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1240) 02-01 16:31:13.684: E/AndroidRuntime(9739): at android.os.Handler.dispatchMessage(Handler.java:99) 02-01 16:31:13.684: E/AndroidRuntime(9739): at android.os.Looper.loop(Looper.java:137) 02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.ActivityThread.main(ActivityThread.java:5039) 02-01 16:31:13.684: E/AndroidRuntime(9739): at java.lang.reflect.Method.invokeNative(Native Method) 02-01 16:31:13.684: E/AndroidRuntime(9739): at java.lang.reflect.Method.invoke(Method.java:511) 02-01 16:31:13.684: E/AndroidRuntime(9739): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) 02-01 16:31:13.684: E/AndroidRuntime(9739): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) 02-01 16:31:13.684: E/AndroidRuntime(9739): at dalvik.system.NativeStart.main(Native Method) 02-01 16:31:13.684: E/AndroidRuntime(9739): Caused by: java.lang.NullPointerException 02-01 16:31:13.684: E/AndroidRuntime(9739): at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:528) 02-01 16:31:13.684: E/AndroidRuntime(9739): at io.openkit.OKLoginActivity.onRestoreInstanceState(OKLoginActivity.java:62) 02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.Activity.performRestoreInstanceState(Activity.java:910) 02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1131) 02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2158) 

Dentro de su DialogFragment, llama Fragment.setRetainInstance (boolean) con el valor true. No es necesario guardar el fragmento manualmente, el marco ya se encarga de todo esto. Al llamar a esto se evitará que su fragmento se destruya durante la rotación y sus solicitudes de red no se verán afectadas.

Puede que tenga que agregar este código para evitar que su diálogo se rechace en rotación, debido a un error con la biblioteca de compatibilidad:

 @Override public void onDestroyView() { Dialog dialog = getDialog(); // handles https://code.google.com/p/android/issues/detail?id=17423 if (dialog != null && getRetainInstance()) { dialog.setDismissMessage(null); } super.onDestroyView(); } 

Una de las ventajas de usar dialogFragment comparación con sólo usar alertDialogBuilder es exactamente porque dialogfragment puede automáticamente recrearse a sí mismo tras la rotación sin la intervención del usuario.

Sin embargo, cuando el fragmento de diálogo no se vuelve a crear, es posible que sobrescriba onSaveInstanceState pero no para llamar a super :

 @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // <-- must call this if you want to retain dialogFragment upon rotation ... } 

Este es un método de conveniencia que utiliza la corrección de la respuesta de antonyt:

 public class RetainableDialogFragment extends DialogFragment { public RetainableDialogFragment() { setRetainInstance(true); } @Override public void onDestroyView() { Dialog dialog = getDialog(); // handles https://code.google.com/p/android/issues/detail?id=17423 if (dialog != null && getRetainInstance()) { dialog.setDismissMessage(null); } super.onDestroyView(); } } 

Sólo deje que su DialogFragment ampliar esta clase y todo estará bien. Esto se convierte especialmente útil, si tiene varios DialogFragments en su proyecto que todos necesitan esta corrección.

  • Solución para el error de Android relacionado con setRetainInstance (true)
  • Cómo extender LinearLayout correctamente para crear una vista personalizada
  • Añadir Fragmento anidado después de que la vista Fragmento de padre ya esté creada
  • Android Espresso: ViewPager no tiene instancia de adaptador
  • Pestañas de Viewpager Fragmento y Fragmentos normales
  • Práctica recomendada para fragmentos anidados en Android 4.0, 4.1 (<4.2) sin utilizar la biblioteca de soporte
  • Mostrar DialogFragment con animación creciendo desde un punto
  • ¿Cómo cierro el teclado cuando se abre el cajón de navegación?
  • GetSupportFragmentManager (). FindFragmentById () devuelve null
  • Cómo determinar cuándo Fragmento se vuelve visible en ViewPager
  • Obtener fragmento actual y guardar en onSaveInstanceState () Método para la orientación de pantalla
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.