Callback de DialogFragment en el cambio de orientación

Estoy migrando mis diálogos, actualmente usando Activity.showDialog(DIALOG_ID); , Para utilizar el sistema DialogFragment como se describe en la referencia de android .

Hay una pregunta que surgió durante mi desarrollo al usar devoluciones de llamada para devolver algún evento a la actividad / fragmento que abrió el diálogo:

He aquí algunos ejemplos de código de un diálogo sencillo:

 public class DialogTest extends DialogFragment { public interface DialogTestListener { public void onDialogPositiveClick(DialogFragment dialog); } // Use this instance of the interface to deliver action events static DialogTestListener mListener; public static DialogTest newInstance(Activity activity, int titleId, int messageId) { udateListener(activity); DialogTest frag = new DialogTest(); Bundle args = new Bundle(); args.putInt("titleId", titleId); args.putInt("messageId", messageId); frag.setArguments(args); return frag; } public static void udateListener(Activity activity) { try { // Instantiate the NoticeDialogListener so we can send events with it mListener = (DialogTestListener) activity; } catch (ClassCastException e) { // The activity doesn't implement the interface, throw exception throw new ClassCastException(activity.toString() + " must implement DialogTestListener"); } } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { int titleId = getArguments().getInt("titleId"); int messageId = getArguments().getInt("messageId"); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); // dialog title builder.setTitle(titleId); // dialog message builder.setMessage(messageId); // dialog negative button builder.setNegativeButton("No", new OnClickListener() { public void onClick(DialogInterface dialog, int id) {}}); // dialog positive button builder.setPositiveButton("Yes", new OnClickListener() { public void onClick(DialogInterface dialog, int id) { mListener.onDialogPositiveClick(DialogTest.this); }}); // create the Dialog object and return it return builder.create(); }} 

Y aquí hay un código de actividad que lo llama:

 public class SomeActivity extends FragmentActivity implements DialogTestListener { private EditText mUserName; @Override public void onCreate(Bundle savedInstanceState) { // setup ui super.onCreate(savedInstanceState); setContentView(R.layout.ui_user_edit); // name input mUserName = (EditText) findViewById(R.id.userEdit_editTextName); } @Override public void onDialogPositiveClick(DialogFragment dialog) { Log.d(TAG, this.toString()); mUserName.setText(mUserName.getText() + "1"); } private void showDialog() { DialogTest test = DialogTest.newInstance(SomeActivity.this, R.string.someTitleText, R.string.someMessageText); test.show(getSupportFragmentManager(), "testDialog"); }} 

El código es más o menos lo que ves la referencia. El problema es que, una vez que se hace un cambio de orientación, cuando se muestra un cuadro de diálogo, deja de funcionar como se esperaba -> Debido al ciclo de vida de la actividad, tanto la actividad como el diálogo se reconstruyen y el cuadro de diálogo no tiene Referencia a la nueva actividad reconstruida.

He añadido el código siguiente a mis actividades onResume método:

  @Override protected void onResume() { super.onResume(); DialogTest.udateListener(this); } 

Haciendo esto, obtengo el comportamiento esperado y el diálogo envía eventos de nuevo a la nueva actividad reconstruida cuando ocurrió un cambio de orientación.

Mi pregunta es: ¿Cuál es la "mejor práctica" para manejar las devoluciones de llamada entre el DialogFragment que fue abierto por un FragmentActivity durante un cambio de orientación?

Atentamente

Sí, esta es una trampa común que estoy cayendo todo el tiempo yo mismo. En primer lugar permítanme decirles que su solución de llamada DialogTest.udateListener() en onResume() parece ser totalmente apropiado para mí.

Una forma alternativa sería utilizar un ResultReceiver que se puede serializar como Parcelable :

 public class DialogTest extends DialogFragment { public static DialogTest newInstance(ResultReceiver receiver, int titleId, int messageId) { DialogTest frag = new DialogTest(); Bundle args = new Bundle(); args.putParcelable("receiver", receiver); args.putInt("titleId", titleId); args.putInt("messageId", messageId); frag.setArguments(args); return frag; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { int titleId = getArguments().getInt("titleId"); int messageId = getArguments().getInt("messageId"); ResultReceiver receiver = getArguments().getParcelable("receiver"); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); // dialog title builder.setTitle(titleId); // dialog message builder.setMessage(messageId); // dialog negative button builder.setNegativeButton("No", new OnClickListener() { public void onClick(DialogInterface dialog, int id) { receiver.sendResult(Activity.RESULT_CANCEL, null); }}); // dialog positive button builder.setPositiveButton("Yes", new OnClickListener() { public void onClick(DialogInterface dialog, int id) { receiver.sendResult(Activity.RESULT_OK, null); }}); // create the Dialog object and return it return builder.create(); }} 

Entonces usted puede manejar todo en el receptor como esto:

 protected void onReceiveResult(int resultCode, Bundle resultData) { if (getActivity() != null){ // Handle result } } 

Comprobar ResultReceiver no sobrevive a la rotación de la pantalla para más detalles. Así que al final probablemente todavía necesitas volver a ResultReceiver el ResultReceiver con tu Activity . La única diferencia es que desacoplar la Activity del DialogFragment .

Hay mejor solución en lugar de utilizar métodos estáticos y variables, ya que funcionaría sólo para una instancia de su diálogo. Es mejor almacenar su devolución de llamada como miembro no estático

 private DialogTestListener mListener; public void setListener (DialogTestListener listener){ mListener = listener; } 

Entonces debe mostrar su diálogo usando TAG como este mDialogFragment.show(getSupportFragmentManager(), DIALOG_TAG);

Y luego en el método onResume de su actividad puede restablecer su oyente

 protected void onResume() { super.onResume(); mDialogFragment = (CMFilterDialogFrg) getSupportFragmentManager().findFragmentByTag(DIALOG_TAG); if(mDialogFragment != null){ mDialogFragment.setListener(yourListener) } } 

Mientras que la solución de André funciona, una mejor solución es obtener la actividad actualizada durante onAttach() en su Fragment .

 private DialogTestListener mListener; @Override public void onAttach(Activity activity) { super.onAttach(activity); mListener = (DialogTestListener) activity; } 

Con esta solución, no necesitará pasar la Activity en newInstance() . Sólo necesita asegurarse de que la Activity posee su Fragment es DialogTestListener . Tampoco es necesario guardar el estado como en la solución ResultReceiver .

Primero, llame a setTargetFragment de FragmentParent para iniciar dialogFragment . En dialogFragment use getTargetFragment para devolver el fragmento de retorno y devolver los datos. Todos los resultados de los datos se expondrán en un onactivityresult de onactivityresult de FragmentParent

Siga este enlace: Recibir resultados de DialogFragment

Otra manera es que usted puede parar la actividad que consigue recreada. Tienes que decirle a Android que manejarás el cambio de orientación tú mismo y que Android no volverá a crear tu actividad. Debe agregar esto para su actividad a su archivo de manifiesto:

 android:configChanges="keyboardHidden|orientation" 

Si no es así, entonces puede usar el estándar onSaveInstanceState() para guardar su estado y recuperar usando savedInstanceState según lo recomendado por Google.

Aquí está la guía oficial de Google para él: http://developer.android.com/guide/components/activities.html#Lifecycle

Ir a través de ella si no lo han hecho ya. Realmente te ayudará en el desarrollo de Android.

  • Configurar la altura y el ancho del diálogo personalizado
  • Android: mostrando un diálogo de progreso
  • ¿Es posible que cuando haga clic edittext mostrará mensaje de diálogo?
  • SetTitle to AppCompatDialog no funciona
  • ¿Cómo puedo mostrar mi actividad como un diálogo en Android?
  • Android: cómo crear una actividad transparente con temas de diálogo
  • Definición de la actividad de android como diálogo con tema de luz
  • Finalizar la actividad en la clase de diálogo
  • Uso de Diálogos vs Actividades
  • Android: no se puede obtener valor de EditText dentro de Custom Dialog
  • Uso de DatePicker sin selector de día
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.