android - full - open dialog fragment from activity
Cómo retener correctamente un DialogFragment a través de la rotación? (3)
Dentro de su DialogFragment
, llame a Fragment.setRetainInstance(boolean)
con el valor true
. No es necesario guardar el fragmento manualmente, el marco ya se ocupa de todo esto. Llamar a esto evitará que su fragmento se destruya durante la rotación y sus solicitudes de red no se verán afectadas.
Es posible que deba agregar este código para evitar que su diálogo se descarte en la rotación, debido a un bug 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();
}
Tengo una FragmentActivity que alberga un DialogFragment.
DialogFragment realiza solicitudes de red y maneja la autenticación de Facebook, por lo que debo conservarla durante la rotación.
He leído todas las demás preguntas relacionadas con este tema, pero ninguna de ellas ha resuelto el problema.
Estoy usando putFragment y getFragment para guardar la instancia de 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 evitar que se descarte el diálogo durante la rotación, pero hasta ahora no puedo retener la instancia.
Alguna idea de lo que va mal?
Así es como se ve mi código 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);
}
}
Esta es la traza de pila de excepción:
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)
Este es un método práctico que utiliza la solució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();
}
}
Solo deja que tu DialogFragment
extienda esta clase y todo estará bien. Esto resulta especialmente útil si tiene múltiples DialogFragments
en su proyecto que necesitan esta solución.
Una de las ventajas de usar dialogFragment
comparación con el uso de alertDialogBuilder
es exactamente porque el fragmento de diálogo puede recrearse automáticamente al girar sin intervención del usuario.
Sin embargo, cuando el fragmento de diálogo no se recrea a sí mismo, es posible que sobrescriba onSaveInstanceState
pero no llame a super
:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); // <-- must call this if you want to retain dialogFragment upon rotation
...
}