example dialogo codepath android dialog callback orientation-changes android-dialogfragment

dialogo - input dialog fragment android



Devolución de llamada de DialogFragment en cambio de orientación (5)

Estoy migrando mis diálogos, actualmente estoy usando Activity.showDialog(DIALOG_ID); , para usar 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:

Aquí hay un código de ejemplo de un diálogo simple:

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 llamándolo:

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 prácticamente lo que ves en la referencia. El problema es que, una vez que realiza 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 cuadro de diálogo se reconstruyen, y el cuadro de diálogo ahora no tiene la configuración adecuada. Referencia a la nueva actividad reconstruida.

Agregué el siguiente código a mis actividades en el método de Reanudar:

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

Al hacer esto, obtengo el comportamiento esperado y el cuadro de diálogo envía los eventos a la nueva actividad reconstruida cuando se produce 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


Hay una mejor solución en lugar de usar métodos y variables estáticos porque funcionaría solo 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 debería 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 escucha

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, ya no tendrá que pasar la Activity en newInstance() . Solo debes asegurarte de que la Activity posee tu Fragment sea ​​un DialogTestListener . Tampoco necesita guardar el estado como en la solución ResultReceiver .


Otra forma es que puedas detener la recreación de la actividad. Tienes que decirle a Android que manejarás el cambio de orientación y 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 puedes usar el estándar onSaveInstanceState() para guardar tu estado y recuperarlo utilizando savedInstanceState como lo recomienda Google.

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

Revísalo si aún no lo has hecho. Realmente te ayudará en el desarrollo de Android.


Primero, llame a setTargetFragment desde FragmentParent para iniciar dialogFragment . En dialogFragment use getTargetFragment para devolver el fragmento de devolución y devolver los datos. El resultado de todos los datos se ejecutará en un onactivityresult de onactivityresult de FragmentParent

siga este enlace: Recibir el resultado de DialogFragment


Sí, esta es una trampa común en la que me estoy cayendo todo el tiempo. En primer lugar, permítame decir que su solución de llamar a DialogTest.udateListener() en onResume() parece ser completamente apropiada para mí.

Una forma alternativa sería utilizar un ResultReceiver que se puede serializar como un 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 puedes manejar todo en el Receptor de esta manera:

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

Echa un vistazo a ResultReceiver no sobrevive a la rotación de la pantalla para obtener más detalles. Entonces, al final, es probable que aún deba volver a cablear el ResultReceiver con su Activity . La única diferencia es que se desacopla la Activity del DialogFragment .