14

I'm converting some of my project to use fragments. How do we communicate with a fragment dialog? I want to create a fragment dialog just to get some text input from the user. When the dialog is dismissed, I'd like to pass the entered text back to the "parent" fragment (the one that started it). Example:

public class MyFragment extends Fragment {

    public void onBtnClick() {
        // What's a good way to get data back from this dialog 
        // once it's dismissed?
        DialogFragment dlgFrag = MyFragmentDialog.newInstance();
        dlgFrag.show(getFragmentManager(), "dialog"); 
    }
}

Thanks

user291701
  • 38,411
  • 72
  • 187
  • 285

4 Answers4

30

As eternalmatt said the given solution does not really answer the question. The way to communicate the dialog with the fragment is calling:

dialog.setTargetFragment(myCallingFragment, requestCode);

The way I do this is by creating the FragmentDialog with an static method where the listener is instanciated an then do the setFragmentTarget() stuff:

public mySuperFragmentDialog extends DialogFragment {
  public interface SuperListener{
     void onSomethingHappened();
  }

  public static mySuperFragmentDialog newInstance(SuperListener listener){
     MySuperFagmentDialog f = new MySuperFragmentDialog();
     f.setTargetFragment((Fragment) listener, /*requestCode*/ 1234);
     return f;
  }
}

To create the dialog from the fragment just do as usual:

Dialog dialog = MySuperFragmentDialog.newInstance(parentFragment);
dialog.show();

Then when you want to comunicate with the fragment which calls the dialog just:

Fragment parentFragment = getTargetFragment();
((SuperListener) parentFragment).onSomethingHappened();

This solution works only when dialog is gonna be created from Fragments and not from Activities, but you can combine both methods ('setFragmentTarget()' and the 'onAttach()' one) plus some Class checks to provide a full solution.

IntelliJ Amiya
  • 74,896
  • 15
  • 165
  • 198
juanmeanwhile
  • 2,594
  • 2
  • 24
  • 26
  • Why is it public static mySuperFragmentDialog newInstance and not public static void newInstance. I don't see any return statement in here. –  Nov 07 '13 at 21:35
  • @juanmeanwhile thanks for the info! but from where we need to listener is instantiate the SuperListener listener? – LOG_TAG Nov 11 '13 at 07:37
  • @juanmeanwhile getting error for f.setTargetFragment((Fragment) listener java.lang.ClassCastException: android.support.v4.app.Fragment E/AndroidRuntime(1451): java.lang.ClassCastException: com... cannot be cast to android.support.v4.app.Fragment – LOG_TAG Nov 11 '13 at 08:23
  • @LOG_TAG Are you creating the dialog from a Fragment or from an Activity? If you create the dialog from the Activity it will produce this ClassCastException. When creating dialog from an Activity you should avoid using setTargetFragment() (you can just comment it) and add the method: public void onAttach(Activity activity){ mListener = (OnArticleSelectedListener) activity; } You will need to create a field OnArticleSelectedListener mListener; and call the method from that var instead of the getFragmentTarget(). – juanmeanwhile Nov 11 '13 at 14:58
  • @juanmeanwhile from fragment I'm trying! have look at this answer http://stackoverflow.com/questions/13238959/how-to-get-button-clicks-in-host-fragment-from-dialog-fragment I just put the setTargetFragment at the fragment where I'm calling the dialog fragment ! – LOG_TAG Nov 12 '13 at 04:36
  • @LOG_TAG Could you create a question and put here a link to it so I can check your code? It will be easier to detect what is going on. – juanmeanwhile Nov 12 '13 at 18:02
  • 1
    @juanmenawhile, why not do something like this: if (getTargetFragment() != null) { ((SuperListener) getTargetFragment()).onSomethingHappened(); } else { ((SuperListener) getActivity()).onSomethingHappened(); } Assuming that when you call from a fragment you set the setTargetFragment you can control easily if its from a fragment or activity.... – Maxrunner Jan 29 '14 at 16:16
  • doesn't the getActivity method returns the current parent activity associated with the dialogfragment? – Maxrunner Jan 29 '14 at 16:38
  • 1
    That is correct @Maxrunner, the only advantage I may found the other way is that you are casting the activity (or fragment) at dialog creation and you will get a ClassException sooner in case you forget to implement dthe listener interface. But works the same way :) – juanmeanwhile Jan 30 '14 at 17:03
  • But, views in parent fragment is become null..., How to solve this one – Kumar Kalluri May 20 '14 at 14:23
  • When you create a DialogFragment from a parent fragment parent views are not null, or at least It hasn't happened to me (or I dont understand the case you are talking about) – juanmeanwhile May 21 '14 at 16:20
14

A great way to pass this kind of Events is a Callback Interface like descripted in the Android Developers Guide

Your Fragment define a Callback Interface like

public class MyFragment extends Fragment {
    ...
    // Container Activity must implement this interface
    public interface OnArticleSelectedListener {
        public void onArticleSelected(Uri articleUri);
    }
    ...
}

Then you check inside your onAttach Method if the Parent implemented the Callback Interface and save the Instance.

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    try {
        mListener = (OnArticleSelectedListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
    }
}

when your Event inside the Fragment happens you simply call the Callback Handler

mListener.onArticleSelected(...);

Hope that helps, further infos here

Michele
  • 6,126
  • 2
  • 41
  • 45
  • 21
    This does not answer OP's question. He would like to communicate back to the fragment `MyFragment` and this would allow him to communicate back to the activity which started `MyFragment`. – eternalmatt Dec 05 '12 at 21:27
  • 4
    This is how to communicate between an Activity and a Fragment. To communicate between Fragments, use `setTargetFragment()` and `getTargetFragment()`. – Matt Quigley Jun 05 '13 at 05:56
  • 2
    I'd like to add to this answer: __DO NOT PASS ANYTHING VIA THE CONSTRUCTOR__ it is essential that the constructor can be called with no arguments (default constructed in C++ terms), use `onAttach`, as this answer does – Alec Teal Feb 07 '14 at 22:19
0

I had this problem once and after I solved it, I created a project that would remind me how I did it. I put the project on github so anyone can see the solution. Here is the link: https://github.com/mumasaba/FragmentFragmentBoss

In this project, we have a simple app with a TextView displaying the words 'Hello World'. This text view is on a fragment which is hosted by the main app activity. This fragment needs to display a new word that the user can enter after they click on the add options menu icon. When clicked, the options menu item calls up a dialog allowing the user to type in their new word. After the user is done, they can click ok to dismiss the dialog and display their new input on the fragment's text view. Therefore, Fragment to DialogFragment communication is illustrated.

Mumasaba
  • 1
  • 1
0

There is a new pattern possible which is to share a ViewModel instance between fragments. When instantiating a ViewModelFactory where to get your ViewModels, you have to specify a context as parameter. If the context is the same for both fragments (i.e: the parent activity or parent fragment) and you instantiate the same ViewModel from both fragments, you will get the same instance. This opens a new range of possibilities but also challenges.

juanmeanwhile
  • 2,594
  • 2
  • 24
  • 26