onattach from ejemplo android android-fragments callback android-dialogfragment

android - from - dialogfragment onattach fragment



DevoluciĆ³n de llamada a un fragmento de un DialogFragment (11)

Debe definir una interface en su clase de fragmento e implementar esa interfaz en su actividad principal. Los detalles se detallan aquí http://developer.android.com/guide/components/fragments.html#EventCallbacks . El código sería similar a:

Fragmento:

public static class FragmentA extends DialogFragment { OnArticleSelectedListener mListener; // Container Activity must implement this interface public interface OnArticleSelectedListener { public void onArticleSelected(Uri articleUri); } @Override public void onAttach(Activity activity) { super.onAttach(activity); try { mListener = (OnArticleSelectedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener"); } } }

Actividad:

public class MyActivity extends Activity implements OnArticleSelectedListener{ ... @Override public void onArticleSelected(Uri articleUri){ } ... }

Pregunta: ¿Cómo se crea una devolución de llamada desde un DialogFragment a otro Fragment? En mi caso, la actividad involucrada debería ser completamente inconsciente de DialogFragment.

Considera que tengo

public class MyFragment extends Fragment implements OnClickListener

Entonces, en algún momento podría hacer

DialogFragment dialogFrag = MyDialogFragment.newInstance(this); dialogFrag.show(getFragmentManager, null);

Donde se ve MyDialogFragment

protected OnClickListener listener; public static DialogFragment newInstance(OnClickListener listener) { DialogFragment fragment = new DialogFragment(); fragment.listener = listener; return fragment; }

Pero no hay garantía de que el oyente estará presente si DialogFragment hace una pausa y se reanuda a lo largo de su ciclo de vida. Las únicas garantías en un Fragmento son aquellas pasadas a través de un Paquete a través de setArguments y getArguments.

Hay una forma de referenciar la actividad si debe ser el oyente:

public Dialog onCreateDialog(Bundle bundle) { OnClickListener listener = (OnClickListener) getActivity(); .... return new AlertDialog.Builder(getActivity()) ........ .setAdapter(adapter, listener) .create(); }

Pero no quiero que la Actividad escuche eventos, necesito un Fragmento. Realmente, podría ser cualquier objeto Java que implemente OnClickListener.

Considere el ejemplo concreto de un Fragmento que presenta un AlertDialog a través de DialogFragment. Tiene botones Sí / No. ¿Cómo puedo enviar estos botones nuevamente al Fragmento que lo creó?


Estaba enfrentando un problema similar. La solución que descubrí fue:

  1. Declare una interfaz en su DialogFragment tal como James McCracken lo explicó anteriormente.

  2. Implemente la interfaz en su actividad (¡no fragmento! Esa no es una buena práctica).

  3. Desde el método de devolución de llamada en su actividad, llame a una función pública requerida en su fragmento que hace el trabajo que desea hacer.

Por lo tanto, se convierte en un proceso de dos pasos: DialogFragment -> Activity y luego Activity -> Fragment


La actividad involucrada es completamente inconsciente de DialogFragment.

Clase de fragmento:

public class MyFragment extends Fragment { int mStackLevel = 0; public static final int DIALOG_FRAGMENT = 1; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { mStackLevel = savedInstanceState.getInt("level"); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("level", mStackLevel); } void showDialog(int type) { mStackLevel++; FragmentTransaction ft = getActivity().getFragmentManager().beginTransaction(); Fragment prev = getActivity().getFragmentManager().findFragmentByTag("dialog"); if (prev != null) { ft.remove(prev); } ft.addToBackStack(null); switch (type) { case DIALOG_FRAGMENT: DialogFragment dialogFrag = MyDialogFragment.newInstance(123); dialogFrag.setTargetFragment(this, DIALOG_FRAGMENT); dialogFrag.show(getFragmentManager().beginTransaction(), "dialog"); break; } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch(requestCode) { case DIALOG_FRAGMENT: if (resultCode == Activity.RESULT_OK) { // After Ok code. } else if (resultCode == Activity.RESULT_CANCELED){ // After Cancel code. } break; } } } }

Clase DialogFragment:

public class MyDialogFragment extends DialogFragment { public static MyDialogFragment newInstance(int num){ MyDialogFragment dialogFragment = new MyDialogFragment(); Bundle bundle = new Bundle(); bundle.putInt("num", num); dialogFragment.setArguments(bundle); return dialogFragment; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { return new AlertDialog.Builder(getActivity()) .setTitle(R.string.ERROR) .setIcon(android.R.drawable.ic_dialog_alert) .setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, getActivity().getIntent()); } } ) .setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_CANCELED, getActivity().getIntent()); } }) .create(); } }


La forma correcta de configurar un oyente a un fragmento es configurándolo cuando está conectado . El problema que tenía era que enAttachFragment nunca se llamó, después de algunas investigaciones me di cuenta de que había estado usando getFragmentManager en lugar de getChildFragmentManager

Así es como lo hago:

MyDialogFragment dialogFragment = MyDialogFragment.newInstance("title", "body"); dialogFragment.show(getChildFragmentManager(), "SOME_DIALOG");

Adjúntalo enAttachFragment:

@Override public void onAttachFragment(Fragment childFragment) { super.onAttachFragment(childFragment); if (childFragment instanceof MyDialogFragment) { MyDialogFragment dialog = (MyDialogFragment) childFragment; dialog.setListener(new MyDialogFragment.Listener() { @Override public void buttonClicked() { } }); } }


La guía Comunicación con Otros Fragmentos dice que los Fragmentos deberían comunicarse a través de la Actividad asociada .

A menudo, deseará que un Fragmento se comunique con otro, por ejemplo, para cambiar el contenido en función de un evento del usuario. Toda la comunicación de Fragmento a Fragmento se realiza a través de la Actividad asociada. Dos fragmentos nunca deberían comunicarse directamente.


La solución TargetFragment no parece la mejor opción para los fragmentos de diálogo porque puede crear IllegalStateException después de que la aplicación se destruye y IllegalStateException crear. En este caso, FragmentManager no pudo encontrar el fragmento de destino y obtendrá una IllegalStateException con un mensaje como este:

"Fragmento ya no existe para la clave android: target_state: índice 1"

Parece que Fragment#setTargetFragment() no está destinado a la comunicación entre un Fragmento primario y secundario, sino más bien para la comunicación entre Fragmentos hermanos.

Entonces, una forma alternativa es crear fragmentos de diálogo como este utilizando ChildFragmentManager del fragmento principal, en lugar de usar las actividades FragmentManager :

dialogFragment.show(ParentFragment.this.getChildFragmentManager(), "dialog_fragment");

Y al usar una interfaz, en el método onCreate de DialogFragment puede obtener el fragmento principal:

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); try { callback = (Callback) getParentFragment(); } catch (ClassCastException e) { throw new ClassCastException("Calling fragment must implement Callback interface"); } }

Lo único que queda es llamar a su método de devolución de llamada después de estos pasos.

Para obtener más información sobre el problema, puede consultar el enlace: https://code.google.com/p/android/issues/detail?id=54520


Obtengo el resultado de Fragment DashboardLiveWall (fragmento de llamada) de Fragment LiveWallFilterFragment (fragmento de recepción) Como este ...

LiveWallFilterFragment filterFragment = LiveWallFilterFragment.newInstance(DashboardLiveWall.this ,""); getActivity().getSupportFragmentManager().beginTransaction(). add(R.id.frame_container, filterFragment).addToBackStack("").commit();

dónde

public static LiveWallFilterFragment newInstance(Fragment targetFragment,String anyDummyData) { LiveWallFilterFragment fragment = new LiveWallFilterFragment(); Bundle args = new Bundle(); args.putString("dummyKey",anyDummyData); fragment.setArguments(args); if(targetFragment != null) fragment.setTargetFragment(targetFragment, KeyConst.LIVE_WALL_FILTER_RESULT); return fragment; }

setResult vuelve a llamar fragmento como

private void setResult(boolean flag) { if (getTargetFragment() != null) { Bundle bundle = new Bundle(); bundle.putBoolean("isWorkDone", flag); Intent mIntent = new Intent(); mIntent.putExtras(bundle); getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, mIntent); } }

onActivityResult

@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == Activity.RESULT_OK) { if (requestCode == KeyConst.LIVE_WALL_FILTER_RESULT) { Bundle bundle = data.getExtras(); if (bundle != null) { boolean isReset = bundle.getBoolean("isWorkDone"); if (isReset) { } else { } } } } }


Resolví esto de una manera elegante con RxAndroid. Reciba un observador en el constructor de DialogFragment y suscríbase a observable y presione el valor cuando se llame a la devolución de llamada. Luego, en su Fragment, cree una clase interna del Observer, cree una instancia y páselo al constructor del DialogFragment. Usé WeakReference en el observador para evitar pérdidas de memoria. Aquí está el código:

BaseDialogFragment.java

import java.lang.ref.WeakReference; import io.reactivex.Observer; public class BaseDialogFragment<O> extends DialogFragment { protected WeakReference<Observer<O>> observerRef; protected BaseDialogFragment(Observer<O> observer) { this.observerRef = new WeakReference<>(observer); } protected Observer<O> getObserver() { return observerRef.get(); } }

DatePickerFragment.java

public class DatePickerFragment extends BaseDialogFragment<Integer> implements DatePickerDialog.OnDateSetListener { public DatePickerFragment(Observer<Integer> observer) { super(observer); } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { // Use the current date as the default date in the picker final Calendar c = Calendar.getInstance(); int year = c.get(Calendar.YEAR); int month = c.get(Calendar.MONTH); int day = c.get(Calendar.DAY_OF_MONTH); // Create a new instance of DatePickerDialog and return it return new DatePickerDialog(getActivity(), this, year, month, day); } @Override public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) { if (getObserver() != null) { Observable.just(month).subscribe(getObserver()); } } }

MyFragment.java

//Show the dialog fragment when the button is clicked @OnClick(R.id.btn_date) void onDateClick() { DialogFragment newFragment = new DatePickerFragment(new OnDateSelectedObserver()); newFragment.show(getFragmentManager(), "datePicker"); } //Observer inner class private class OnDateSelectedObserver implements Observer<Integer> { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(Integer integer) { //Here you invoke the logic } @Override public void onError(Throwable e) { } @Override public void onComplete() { } }

Puede ver el código fuente aquí: https://github.com/andresuarezz26/carpoolingapp


Seguí estos sencillos pasos para hacer esto.

  1. Cree una interfaz como DialogFragmentCallbackInterface con algún método, como callBackMethod(Object data) . Que llamarías para pasar datos.
  2. Ahora puede implementar la interfaz DialogFragmentCallbackInterface en su fragmento como MyFragment implements DialogFragmentCallbackInterface
  3. En el momento de la creación de DialogFragment establezca el fragmento de invocación MyFragment como fragmento de destino que creó DialogFragment use myDialogFragment.setTargetFragment(this, 0) check setTargetFragment (Fragment fragment, int requestCode)

    MyDialogFragment dialogFrag = new MyDialogFragment(); dialogFrag.setTargetFragment(this, 1);

  4. Obtenga su objeto de fragmento de destino en su DialogFragment llamando a getTargetFragment() y DialogFragmentCallbackInterface a DialogFragmentCallbackInterface . Ahora puede usar esta interfaz para enviar datos a su fragmento.

    DialogFragmentCallbackInterface callback = (DialogFragmentCallbackInterface) getTargetFragment(); callback.callBackMethod(Object data);

    ¡Eso es todo! solo asegúrate de haber implementado esta interfaz en tu fragmento.


Tal vez un poco tarde, pero puede ayudar a otras personas con la misma pregunta que yo.

Puede usar setTargetFragment en Dialog antes de mostrar, y en el cuadro de diálogo puede llamar a getTargetFragment para obtener la referencia.


Actualizado:

@CallbackFragment una biblioteca basada en mi código de idea que genera esos @CallbackFragment para ti usando @CallbackFragment y @Callback .

https://github.com/zeroarst/callbackfragment .

Y el ejemplo le da el ejemplo que envía una devolución de llamada de un fragmento a otro fragmento.

Respuesta anterior:

Hice una BaseCallbackFragment y una anotación @FragmentCallback . Actualmente se extiende Fragment , puedes cambiarlo a DialogFragment y funcionará. Comprueba las implementaciones con el siguiente orden: getTargetFragment ()> getParentFragment ()> context (activity).

Entonces solo necesita extenderlo y declarar sus interfaces en su fragmento y darle la anotación, y el fragmento base hará el resto. La anotación también tiene un parámetro mandatory para que pueda determinar si desea forzar al fragmento a implementar la devolución de llamada.

public class EchoFragment extends BaseCallbackFragment { private FragmentInteractionListener mListener; @FragmentCallback public interface FragmentInteractionListener { void onEcho(EchoFragment fragment, String echo); } }

https://gist.github.com/zeroarst/3b3f32092d58698a4568cdb0919c9a93