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:
- Cómo iniciar una actividad desde un diálogo en Android
- SendUserActionEvent () mView == null después de hacer clic en el botón
- ¿Qué significa 'indeterminado' en ProgressDialog?
- Android: ¿Cómo crear un cuadro de diálogo sin título?
- Cómo evitar que un cuadro de diálogo se cierre cuando se hace clic en un botón
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
- ¿Cómo cancelar un diálogo temático como Actividad cuando se toca fuera de la ventana?
- Android - MediaController de VideoView dentro de diálogo aparece detrás del diálogo
- Selector de archivos múltiples / selector de diálogo de Android
- Uso del diálogo de progreso con el hilo
- ¿Cómo crear un diálogo que se parece exactamente a ContextMenu?
- AppCompatActivity como un diálogo sin título
- Incorporar datepicker dentro de un Acitivity
- No se puede agregar ventana - token android.os.BinderProxy@42824 no es válido; ¿Está funcionando su actividad?
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.
- Cómo parar toast & alertDialog perder el foco en mi filtro EditText
- No se pudo cargar lept de loader findLibrary returned null?