Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Android "Best Practice" devolver valores desde un diálogo

¿Cuál es la forma "correcta" de devolver los valores a la actividad de llamada desde un cuadro de diálogo personalizado complejo, por ejemplo, campos de texto, selector de fecha o hora, un montón de botones de radio, etc., más un botón "Guardar" y "Cancelar"?

Algunas de las técnicas que he visto en la web incluyen:

  • Miembros de datos públicos en la clase derivada de diálogo que pueden ser leídos por la actividad

  • Public "get" accessors. . . ". . "

  • Iniciar el diálogo con un controlador de intención (en oposición a show () ) más en la clase de diálogo que toman entrada de los distintos controles y agruparlos para que se devuelvan a la actividad para que cuando el oyente haga clic en "Guardar" el paquete se devuelve Utilizando ReturnIntent ()

  • Los oyentes en la actividad que procesan la entrada de los controles que están en el diálogo, por ejemplo, para que los oyentes de TimePicker o DatePicker estén realmente en la actividad. En este esquema prácticamente todo el trabajo se realiza en la Actividad

  • Un oyente en la actividad para el botón "Guardar" y luego la Actividad interroga directamente los controles en el diálogo; La actividad descarta el diálogo.

… más más que ya he olvidado.

¿Existe una técnica particular que se considera el método canónicamente correcto o "mejor práctica"?

6 Solutions collect form web for “Android "Best Practice" devolver valores desde un diálogo”

Estoy usando la siguiente manera:

  1. Todas mis actividades tienen una y la misma actividad de los padres (digamos ControlActivity). ControlActivity tiene private volatile Bundle controlBundle; Con el getter / setter apropiado
  2. Cuando comienzo el diálogo, solía llamar a diálogo a través de mi propio método:

     public void showMyDialog(int id, Bundle bundle) { this.controlBundle=bundle; this.showDialog(id, bundle); } 

Así que cada vez que conozco los parámetros enviados al diálogo

  1. Cuando el diálogo está a punto de completar, estoy formando en diálogo otro Bundle con los valores necesarios y luego los pongo a través de mi Setter de paquete de Activity :
 ((ControlActivity )this.getOwnerActivity).setControlBundle(bundle); 

Así que al final cuando el diálogo termina sé que el valor "devuelto" del diálogo. Sé que no es como int retCode=this.showMyDialog(); Es un poco más complejo, pero es viable.

Tal vez estoy mal entender su pregunta, pero ¿por qué no sólo utilizar el construido en el sistema de escucha:

 builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // run whatever code you want to run here // if you need to pass data back, just call a function in your // activity and pass it some parameters } }) 

Así es como siempre he manejado los datos de los cuadros de diálogo.

EDIT: Permítanme darles un ejemplo más concreto que mejor responderá a su pregunta. Voy a robar algún código de ejemplo de esta página, que debería leer:

http://developer.android.com/guide/topics/ui/dialogs.html

 // Alert Dialog code (mostly copied from the Android docs AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Pick a color"); builder.setItems(items, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { myFunction(item); } }); AlertDialog alert = builder.create(); 

 // Now elsewhere in your Activity class, you would have this function private void myFunction(int result){ // Now the data has been "returned" (as pointed out, that's not // the right terminology) } 

Para mi aplicación MIDI necesitaba si / no / cancelar los diálogos de confirmación, por lo que primero hice una clase general de StandardDialog:

 public class StandardDialog { import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.os.Handler; public class StandardDialog { public static final int dlgResultOk = 0; public static final int dlgResultYes = 1; public static final int dlgResultNo = 2; public static final int dlgResultCancel = 3; public static final int dlgTypeOk = 10; public static final int dlgTypeYesNo = 11; public static final int dlgTypeYesNoCancel = 12; private Handler mResponseHandler; private AlertDialog.Builder mDialogBuilder; private int mDialogId; public StandardDialog(Activity parent, Handler reponseHandler, String title, String message, int dialogType, int dialogId) { mResponseHandler = reponseHandler; mDialogId = dialogId; mDialogBuilder = new AlertDialog.Builder(parent); mDialogBuilder.setCancelable(false); mDialogBuilder.setTitle(title); mDialogBuilder.setIcon(android.R.drawable.ic_dialog_alert); mDialogBuilder.setMessage(message); switch (dialogType) { case dlgTypeOk: mDialogBuilder.setNeutralButton("Ok", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { mResponseHandler.sendEmptyMessage(mDialogId + dlgResultOk); } }); break; case dlgTypeYesNo: case dlgTypeYesNoCancel: mDialogBuilder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { mResponseHandler.sendEmptyMessage(mDialogId + dlgResultYes); } }); mDialogBuilder.setNegativeButton("No", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { mResponseHandler.sendEmptyMessage(mDialogId + dlgResultNo); } }); if (dialogType == dlgTypeYesNoCancel) { mDialogBuilder.setNeutralButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { mResponseHandler.sendEmptyMessage(mDialogId + dlgResultCancel); } }); } break; } mDialogBuilder.show(); } } 

A continuación, en mi actividad principal ya tenía un manejador de mensajes para las actualizaciones de interfaz de usuario de otros subprocesos, por lo que acaba de agregar código para el procesamiento de mensajes de los diálogos. Mediante el uso de un parámetro diferente de dialogId cuando instancio el StandardDialog para varias funciones de programa, puedo ejecutar el código apropiado para manejar las respuestas yes / no / cancel a diferentes preguntas. Esta idea se puede extender para cuadros de diálogo personalizados complejos enviando un paquete de datos aunque esto es mucho más lento que un simple mensaje entero.

 private Handler uiMsgHandler = new Handler() { @Override public void handleMessage(Message msg) { if (msg != null) { // {Code to check for other UI messages here} // Check for dialog box responses if (msg.what == (clearDlgId + StandardDialog.dlgResultYes)) { doClearDlgYesClicked(); } else if (msg.what == (recordDlgId + StandardDialog.dlgResultYes)) { doRecordDlgYesClicked(); } else if (msg.what == (recordDlgId + StandardDialog.dlgResultNo)) { doRecordDlgNoClicked(); } } } }; 

Entonces todo lo que necesito hacer es definir los métodos do {Whatever} () en la actividad. Para abrir un diálogo, como ejemplo tengo un método que responde a un botón "borrar eventos MIDI grabados" y lo confirmo de la siguiente manera:

 public void onClearBtnClicked(View view) { new StandardDialog(this, uiMsgHandler, getResources().getString(R.string.dlgTitleClear), getResources().getString(R.string.dlgMsgClear), StandardDialog.dlgTypeYesNo, clearDlgId); } 

clearDlgId se define como un entero único en otro lugar. Este método hace que aparezca un cuadro de diálogo Sí / No delante de la actividad, que pierde el foco hasta que se cierra el diálogo, momento en el que la actividad recibe un mensaje con el resultado del diálogo. A continuación, el manejador de mensajes llama al método doClearDlgYesClicked() si se hace clic en el botón "Sí". (No necesitaba un mensaje para el botón "No" ya que no se necesitaba ninguna acción en ese caso).

De todos modos, este método funciona para mí, y hace que sea fácil pasar los resultados de un diálogo.

He reflexionado sobre esto por un tiempo y, finalmente, la forma más conveniente que encontré de hacer esto es romper mi actividad en varios métodos que representan cada unidad de flujo de control. Por ejemplo, si las actividades dentro de mi actividad son decir: carga las variables de la intención, comprobar algunos datos, proceso y proceder si está disponible, si no hacer una llamada de fondo, esperar a la interacción del usuario, iniciar otra actividad.

En general recojo las partes que son comunes, las dos primeras y las últimas en este caso. Voy a envolver los primeros en onCreate() y hacer una separada para el último … decir startAnotherActivity(Data) . Usted puede arreglar las partes medias así que consistirán en un checkData(Data) (posiblemente combinado en el onCreate() ) que llama o processAvailableData(Data) o performBackgroundTask(Data) . La tarea de fondo realizará una operación en el fondo y devolverá el control a onBackgroundTaskCompleted(OtherData) .

Ahora, tanto processAvailableData(Data) como onBackgroundTaskCompleted(OtherData) llaman al método getUserResponse() que a su vez puede llamar a startAnotherActivity(Data) o fusionar sus funciones con sí mismo.

Siento que este enfoque da una serie de beneficios.

  1. Ayuda con el problema de devolución de datos a lo que su pregunta apunta al "avanzar" en lugar de devolver datos.
  2. Permite una adición más fácil de nueva funcionalidad. Por ejemplo, si quisiéramos dar al usuario más opciones, podríamos simplemente llamar al método apropiado de getUserResponse() que podría afectar los datos que eventualmente pasan a la siguiente actividad.
  3. Ayuda a evitar problemas de flujo innecesario (revisa las preguntas relacionadas con finish() y return SO) cuando nuestro supuesto intuitivo es un cierto flujo y resulta ser otro.
  4. Ayuda a administrar las variables mejor para que no terminen teniendo muchos campos de nivel de clase para evitar los problemas de acceso variable en las clases internas anónimas (onClick (), doInBackground (), etc.).

Estoy bastante seguro de tener más métodos agrega algunos gastos generales, pero su probablemente compensado por las ventajas de flujo, reutilización y simplicidad que usted obtiene (me encantaría escuchar las opiniones de un experto de compilación en esto).

Voy a explicar una solución con el ejemplo de dos fragmentos. Imagine que hay un SimpleFragment que tiene sólo un campo de texto para mostrar una fecha. Luego hay un DatePickerFragment que permite elegir una fecha en particular. Lo que quiero es que el DatePickerFragment pasa el valor de fecha de nuevo al SimpleFragment llama cuando el usuario confirma su selección.

SimpleFragment

Por lo tanto, en primer lugar iniciar el DatePickerFragment desde dentro del SimpleFragment :

 private DateTime mFavoriteDate; // Joda-Time date private void launchDatePicker() { DatePickerFragment datePickerFragment = new DatePickerFragment(); Bundle extras = new Bundle(); // Pass an initial or the last value for the date picker long dateInMilliSeconds = mFavoriteDate.getMillis(); extras.putLong(BundleKeys.LAST_KNOWN_DATE, dateInMilliSeconds); datePickerFragment.setArguments(extras); datePickerFragment.setTargetFragment(this, SIMPLE_FRAGMENT_REQUEST_CODE); datePickerFragment.show(getActivity().getSupportFragmentManager(), DatePickerFragment.FRAGMENT_TAG); } 

DatePickerFragment

En el fragmento de diálogo nos preparamos para devolver la fecha seleccionada cuando el usuario pulsa el botón positivo:

 public static final String DATE_PICKED_INTENT_KEY = "DATE_PICKED_INTENT_KEY"; public static final int DATE_PICKED_RESULT_CODE = 123; @Override public Dialog onCreateDialog(Bundle savedInstanceState) { // ... Long dateInMilliSeconds = getArguments().getLong(BundleKeys.LAST_KNOWN_DATE); DateTime date = new DateTime(dateInMilliSeconds); initializePickerUiControl(date); AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(activity); dialogBuilder .setPositiveButton(R.string.date_picker_positive, (dialog, which) -> { // Pass date to caller passBackDate(); }) .setNegativeButton(R.string.date_picker_negative, (dialog, which) -> { // Nothing to do here }); return dialogBuilder.create(); } private void passBackDate() { DateTime dateTime = getDateTimeFromPickerControl(); Intent intent = new Intent(); intent.putExtra(DATE_PICKED_INTENT_KEY, dateTime.getMillis()); getTargetFragment().onActivityResult( getTargetRequestCode(), DATE_PICKED_RESULT_CODE, intent); } 

SimpleFragment

De vuelta en el fragmento solicitante consumimos lo que se ha pasado de vuelta por el diálogo:

 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == SIMPLE_FRAGMENT_REQUEST_CODE && resultCode == DatePickerFragment.DATE_PICKED_RESULT_CODE) { long datePickedInMilliseconds = data.getLongExtra( DatePickerFragment.DATE_PICKED_INTENT_KEY, 0); mFavoriteDate = new DateTime(datePickedInMilliseconds); updateFavoriteDateTextView(); } else { super.onActivityResult(requestCode, resultCode, data); } } 

Referencias a mattpic que dio una excelente respuesta antes.

Después de un poco de investigación me instalé en una interfaz de devolución de llamada. Mi código es el siguiente:

MyFragment.java

 public class MyFragment extends Fragment { 

 private void displayFilter() { FragmentManager fragmentManager = getFragmentManager(); FilterDialogFragment filterDialogFragment = new FilterDialogFragment(); Bundle bundle = new Bundle(); bundle.putSerializable("listener", new FilterDialogFragment.OnFilterClickListener() { @Override public void onFilterClickListener() { System.out.println("LISTENER CLICKED"); } }); filterDialogFragment.setArguments(bundle); filterDialogFragment.show(fragmentManager, DIALOG_FILTER); } 

MyDialog.java

 public class MyDialog extends DialogFragment { private ImageButton mBtnTest; private OnFilterClickListener mOnFilterClickListener; @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); // Get the layout inflater LayoutInflater inflater = getActivity().getLayoutInflater(); View filterLayout = inflater.inflate(R.layout.filter_dialog, null); // Inflate and set the layout for the dialog // Pass null as the parent view because its going in the dialog layout builder.setView(filterLayout) .setTitle("Filter"); Dialog dialog = builder.create(); mOnFilterClickListener = (OnFilterClickListener) getArguments().getSerializable("listener"); mBtnTest = (ImageButton)filterLayout.findViewById(R.id.fandb); mBtnTest.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mOnFilterClickListener.onFilterClickListener(); dismiss(); } }); return dialog; } public interface OnFilterClickListener extends Serializable { void onFilterClickListener(); } } 
FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.