Evitar el descarte del diálogo en la rotación de la pantalla en Android

Estoy intentando evitar que los diálogos creados con el generador de alertas se descarten cuando se reinicie la actividad.

Si sobrecarga el método onConfigurationChanged, puedo hacerlo con éxito y reiniciar el diseño para corregir la orientación, pero pierdo la función de texto fijo de edittext. Entonces al resolver el problema de diálogo, he creado este problema de edición de texto.

Si guardo las cadenas del texto de edición y las vuelvo a asignar en el cambio en configuración, todavía parecen tener el valor inicial predeterminado, no lo que se ingresó antes de la rotación. Incluso si forzo una invalidación, parece actualizarlos.

Realmente necesito resolver el problema del diálogo o el problema del texto de edición.

Gracias por la ayuda.

La mejor forma de evitar este problema hoy en día es usar un DialogFragment .

Crea una nueva clase que amplíe DialogFragment . onCreateDialog y devuelva su Dialog o un AlertDialog .

Luego puede mostrarlo con DialogFragment.show(fragmentManager, tag) .

Aquí hay un ejemplo con un Listener :

 public class MyDialogFragment extends DialogFragment { public interface YesNoListener { void onYes(); void onNo(); } @Override public void onAttach(Activity activity) { super.onAttach(activity); if (!(activity instanceof YesNoListener)) { throw new ClassCastException(activity.toString() + " must implement YesNoListener"); } } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { return new AlertDialog.Builder(getActivity()) .setTitle(R.string.dialog_my_title) .setMessage(R.string.dialog_my_message) .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ((YesNoListener) getActivity()).onYes(); } }) .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ((YesNoListener) getActivity()).onNo(); } }) .create(); } } 

Y en la actividad que llamas:

 new MyDialogFragment().show(getSupportFragmentManager(), "tag"); // or getFragmentManager() in API 11+ 

Esta respuesta ayuda a explicar estas otras tres preguntas (y sus respuestas):

  • Android La mejor manera de evitar que los diálogos se descarten después de una rotación de dispositivo
  • Android DialogFragment vs Dialog
  • ¿Cómo puedo mostrar un DialogFragment usando el paquete de compatibilidad?
 // Prevent dialog dismiss when orientation changes private static void doKeepDialog(Dialog dialog){ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); lp.copyFrom(dialog.getWindow().getAttributes()); lp.width = WindowManager.LayoutParams.WRAP_CONTENT; lp.height = WindowManager.LayoutParams.WRAP_CONTENT; dialog.getWindow().setAttributes(lp); } 
 public static void doLogout(final Context context){ final AlertDialog dialog = new AlertDialog.Builder(context) .setIcon(android.R.drawable.ic_dialog_alert) .setTitle(R.string.titlelogout) .setMessage(R.string.logoutconfirm) .setPositiveButton("Yes", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ... } }) .setNegativeButton("No", null) .show(); doKeepDialog(dialog); } 

Si está cambiando el diseño en el cambio de orientación, no pondría android:configChanges="orientation" en su manifiesto porque de todos modos está recreando las vistas.

Guarde el estado actual de su actividad (como el texto ingresado, el diálogo mostrado, los datos mostrados, etc.) utilizando estos métodos:

 @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); } 

De esta forma, la actividad continúa en Crear nuevamente y luego llama al método onRestoreInstanceState donde puede establecer su valor de EditText nuevamente.

Si desea almacenar objetos más complejos, puede usar

 @Override public Object onRetainNonConfigurationInstance() { } 

Aquí puede almacenar cualquier objeto y, en Crear, solo tiene que llamar a getLastNonConfigurationInstance(); para obtener el Objeto.

Solo agrega android: configChanges = “orientation” con tu elemento de actividad en AndroidManifest.xml

Ejemplo:

  

Esta pregunta fue respondida hace mucho tiempo.

Sin embargo, esta es una solución no hacky y simple que uso para mí.

Hice esta clase de ayuda para mí, para que pueda usarla también en su aplicación.

El uso es:

 PersistentDialogFragment.newInstance( getBaseContext(), RC_REQUEST_CODE, R.string.message_text, R.string.positive_btn_text, R.string.negative_btn_text) .show(getSupportFragmentManager(), PersistentDialogFragment.TAG); 

O

  PersistentDialogFragment.newInstance( getBaseContext(), RC_EXPLAIN_LOCATION, "Dialog title", "Dialog Message", "Positive Button", "Negative Button", false) .show(getSupportFragmentManager(), PersistentDialogFragment.TAG); public class ExampleActivity extends Activity implements PersistentDialogListener{ @Override void onDialogPositiveClicked(int requestCode) { switch(requestCode) { case RC_REQUEST_CODE: break; } } @Override void onDialogNegativeClicked(int requestCode) { switch(requestCode) { case RC_REQUEST_CODE: break; } } } 

Un enfoque muy sencillo es crear los cuadros de diálogo a partir del método onCreateDialog() (ver nota a continuación). Usted los muestra a través de showDialog() . De esta forma, Android maneja la rotación por usted y no tiene que llamar a onPause() en onPause() para evitar un WindowLeak y tampoco tiene que restaurar el diálogo. De los documentos:

Mostrar un cuadro de diálogo administrado por esta actividad. Una llamada a onCreateDialog (int, Bundle) se realizará con el mismo ID la primera vez que se solicite un ID determinado. A partir de entonces, el diálogo se guardará y restaurará automáticamente.

Consulte los documentos de Android showDialog () para obtener más información. Espero que ayude a alguien!

Nota: Si usa AlertDialog.Builder, no llame a show() desde onCreateDialog() , llame a create() lugar. Si usa ProgressDialog, simplemente cree el objeto, establezca los parámetros que necesita y devuélvalo. En conclusión, show() dentro onCreateDialog() causa problemas, solo crea la instancia de Dialog y regresa. ¡Esto debería funcionar! (He tenido problemas al usar showDialog () desde onCreate () -en realidad no se muestra el cuadro de diálogo-, pero si lo usa en onResume () o en una callback de escucha funciona bien).

Puede combinar los métodos onSave / onRestore de Dialog con los métodos Activity onSave / onRestore para mantener el estado del cuadro de diálogo.

Nota: Este método funciona para esos cuadros de diálogo “simples”, como mostrar un mensaje de alerta. No reproducirá el contenido de un WebView incrustado en un Diálogo. Si realmente desea evitar que un diálogo complejo se descarte durante la rotación, intente con el método de Chung IW.

 @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); myDialog.onRestoreInstanceState(savedInstanceState.getBundle("DIALOG")); // Put your codes to retrieve the EditText contents and // assign them to the EditText here. } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // Put your codes to save the EditText contents and put them // to the outState Bundle here. outState.putBundle("DIALOG", myDialog.onSaveInstanceState()); } 

Definitivamente, el mejor enfoque es usar DialogFragment.

Aquí está la solución de la clase contenedora que ayuda a evitar el descarte de diferentes diálogos dentro de un Fragmento (o Actividad con refactorización pequeña). Además, ayuda a evitar la refactorización masiva de código si por alguna razón hay muchos AlertDialogs dispersos entre el código con pequeñas diferencias entre ellos en términos de acciones, apariencia u otra cosa.

 public class DialogWrapper extends DialogFragment { private static final String ARG_DIALOG_ID = "ARG_DIALOG_ID"; private int mDialogId; /** * Display dialog fragment. * @param invoker The fragment which will serve as {@link AlertDialog} alert dialog provider * @param dialogId The ID of dialog that should be shown */ public static  void show(T invoker, int dialogId) { Bundle args = new Bundle(); args.putInt(ARG_DIALOG_ID, dialogId); DialogWrapper dialogWrapper = new DialogWrapper(); dialogWrapper.setArguments(args); dialogWrapper.setTargetFragment(invoker, 0); dialogWrapper.show(invoker.getActivity().getSupportFragmentManager(), null); } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mDialogId = getArguments().getInt(ARG_DIALOG_ID); } @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { return getDialogProvider().getDialog(mDialogId); } private DialogProvider getDialogProvider() { return (DialogProvider) getTargetFragment(); } public interface DialogProvider { Dialog getDialog(int dialogId); } } 

Cuando se trata de Actividad, puede invocar getContext() dentro onCreateDialog() , convertirlo a la interfaz DialogProvider y solicitar un diálogo específico mediante mDialogId . Toda la lógica para tratar con un fragmento objective debe ser eliminada.

Uso de fragmento:

 public class MainFragment extends Fragment implements DialogWrapper.DialogProvider { private static final int ID_CONFIRMATION_DIALOG = 0; @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { Button btnHello = (Button) view.findViewById(R.id.btnConfirm); btnHello.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { DialogWrapper.show(MainFragment.this, ID_CONFIRMATION_DIALOG); } }); } @Override public Dialog getDialog(int dialogId) { switch (dialogId) { case ID_CONFIRMATION_DIALOG: return createConfirmationDialog(); //Your AlertDialog default: throw new IllegalArgumentException("Unknown dialog id: " + dialogId); } } } 

Puedes leer el artículo completo en mi blog ¿Cómo evitar que se descarte el diálogo? y juega con el código fuente .

Tuve un problema similar: cuando la orientación de la pantalla cambió, se onDismiss oyente de onDismiss del diálogo aunque el usuario no descartó el diálogo. Pude onCancel esto usando el oyente onCancel , que se activó cuando el usuario presionó el botón Atrás y cuando el usuario tocó fuera del cuadro de diálogo.

Solo usa

 ConfigurationChanges = Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize 

y la aplicación sabrá cómo manejar la rotación y el tamaño de la pantalla.