How to get data from DialogFragment to a Fragment?
Asked Answered
C

8

33

Imagine, I have FragmentA from which I startDialogFragment (there are EditText in box). How to can I get back the value from the EditText to FragmentA? I try to make something like this, and this but I was not successful.

Collegium answered 2/8, 2013 at 20:13 Comment(1)
#17967105. here returning boolean value instead return the edittext value. Or use a interface.Philippa
L
89

The Fragment.onActivityResult() method is useful in this situation. It takes getTargetRequestCode(), which is a code you set up between fragments so they can be identified. In addition, it takes a request code, normally just 0 if the code worked well, and then an Intent, which you can attach a string too, like so

Intent intent = new Intent();
intent.putExtra("STRING_RESULT", str);

Also, the setTargetFragment(Fragment, requestCode) should be used in the fragment that the result is being sent from to identify it. Overall, you would have code in the requesting fragment that looks like this:

FragmentManager fm = getActivity().getSupportFragmentManager();
DialogFragment dialogFragment = new DialogFragment();
dialogFragment.setTargetFragment(this, REQUEST_CODE);
dialogFragment.show();

The class to send data (the DialogFragment) would use this Fragment we just defined to send the data:

private void sendResult(int REQUEST_CODE) {
    Intent intent = new Intent();
    intent.putStringExtra(EDIT_TEXT_BUNDLE_KEY, editTextString);
    getTargetFragment().onActivityResult(
        getTargetRequestCode(), REQUEST_CODE, intent);
}

To receive the data, we use this type of class in the Fragment which initially started the DialogFragment:

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    // Make sure fragment codes match up 
    if (requestCode == DialogFragment.REQUEST_CODE) {
        String editTextString = data.getStringExtra(
            DialogFragment.EDIT_TEXT_BUNDLE_KEY);

At this point, you have the string from your EditText from the DialogFragment in the parent fragment. Just use the sendResult(int) method in your TextChangeListener() anonymous class so that the text is sent when you need it.

Lyckman answered 2/8, 2013 at 20:36 Comment(4)
Hi and thanks for this solution... Can you help me please? Why my onActivityResult() method can't capture result from my dialog fragment? When I have the same code... Thanks in advance!Amenity
This is the right way to pass the result back to the fragment! Thanks for the example!Domesticate
Small correction in the code (we have to use Activity.RESULT_OK): getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, intent); dismiss();Finalist
This solution is deprecated with Api-28 . see updated approach : https://mcmap.net/q/331358/-how-to-get-data-from-dialogfragment-to-a-fragmentBeaubeauchamp
W
4

Assume a situation that you are uploading some file to server , on clicking of upload button a dialog should open,prompting for title and optional tag.And the dialog itself containing 2 buttons say cancel and continue.

make the UI as you wish by using layout xml file.

then create one class that extending DialogFragment. inflate the layout and initialize views inside onCreateView() method.

Inside that class create one interface

 public interface uploadDialogInterface

   {
       public void senddata(String title, String tag);
   }

    uploadDialogInterface interfaceObj;
    String title="";
    String tag=" ";

And the important thing is you need to override onAttach() method

 @Override
public void onAttach(Context context) {
    super.onAttach(context);
    this.context=context;
    interfaceObj= (uploadDialogInterface) getTargetFragment();
}

And in the on Button click call the interface method like

     @Override
public void onClick(View v) {
    int id=v.getId();
    if(id== R.id.vB_fud_cancel)
    {
        dismiss();
    }
    else if(id== R.id.vB_fud_upload)
    {
        title=mVideotitle.getText().toString();
        tag=mOptionaltag.getText().toString();
        if(mVideotitle.getText().toString().isEmpty()) {
            Snackbar.make(mVideotitle,"Please enter the video title", Snackbar.LENGTH_SHORT).show();
       }else
        {
            interfaceObj.senddata(title,tag);
            dismiss();

        }
    }
}

And inside the Fragment or activity from which you are launching the dialog should contain setTargetFragment attribute.

private void callUploadDialog()
{
    UploadDialogFragment fragment = new UploadDialogFragment();
    fragment.setTargetFragment(this, 0);
    FragmentManager manager = getFragmentManager();
    FragmentTransaction ft = manager.beginTransaction();
    ft.setCustomAnimations(R.anim.fade_in, R.anim.fade_in);
    fragment.show(ft, "UploadDialogFragment");
    fragment.setCancelable(false);
}

And finally you should implement the interface (that was declared inside the dialog fragment) and override the method

@Override
public void senddata(String title,String optionaltag) {
    this.videoTitle=title;
    this.optionalTag=optionaltag;

}

I think this post will be helpful for those who are using dialog fragment for the first time . I was struggled to find the solution . And hopefully this will solve someone's problem in the future. (Sorry for the language)

Whaling answered 7/2, 2018 at 6:43 Comment(1)
And if you rotate after the dialog is opened? Won't that make that interface object reference the old fragment (the one before rotation?). Don't think this will work okAffix
A
4

One of the better and simpler ways to do this is using Android ViewModel.

This helps in easier sharing of data, without the need of sending any data across fragments. You could do this not only for DialogFragments, but also for normal Fragments.

Source: https://developer.android.com/topic/libraries/architecture/viewmodel

Here is what I did

My ViewModel looks as below

import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.ViewModel;

public class PlayerViewModel extends ViewModel {
    private final MutableLiveData<Player> selectedPlayer = new MutableLiveData<>();

    public LiveData<Player> getSelectedPlayer() {
        return selectedPlayer;
    }

    public void selectPlayer(Player player) {
        selectedPlayer.setValue(player);
    }
}

In the Fragment where I select a Player, I use the following code in the onCreate method to bind the ViewModel

playerViewModel = ViewModelProviders.of(getActivity()).get(PlayerViewModel.class);

When a specific Player is selected, use the following (You can use an ArrayAdapter, DialogFragment's selector or anything you want to display list of players)

playerViewModel = ViewModelProviders.of(getActivity()).get(PlayerViewModel.class);

And finally, in the fragment where you need to show the Player information, do the following in the onCreate method

PlayerViewModel model = ViewModelProviders.of(getActivity()).get(PlayerViewModel.class);
model.getSelectedPlayer().observe(this, new Observer<Player>() {
    @Override
    public void onChanged(@Nullable Player selPlayer) {
        if (selPlayer != null)
            player = selPlayer;
            populateData();
        }
    });
Abbatial answered 22/10, 2018 at 18:3 Comment(1)
Thanks! Confirmed working!! Specially when using the new Navigation components library, it's not possible to do it using startActivityForResult. Issue tracker here: issuetracker.google.com/issues/79672220Stanfordstang
W
2

You need to send the data from the dialog back to the activity via a callback method, then have the activity give that data back to the fragment you want it to go to. Just a quick example:

public void datFromDialog(String data){
    MyFragment mf = (MyFragment)getFragmentManager().findFragmentById(r.id.frag);

    mf.iWantNewData(data);
}
Womanly answered 2/8, 2013 at 20:16 Comment(4)
Please,can you explain it more or get more full exapleCollegium
look here developer.android.com/guide/components/…Womanly
you dont communicate between fragment directly, the activity is suppose to do all the communication between fragments. Fragments should not know that any other fragment exists. So basically it works like this. A button is clicked in a fragment that send a callback the the activity to start a dialog. Dialog is up whatever need to be done in there is done and another button is clicked there to send data back to the activity in which the activity will update the other fragment with new dataWomanly
@Womanly how to do the same for childfragment? which doesn't have id?Jewess
D
1

You can use Fragment Result API.

For example;
step 1: navigate Fragment A(from) -> Fragment B(to)
step 2: come back to A
step 3: get result data from B

Fragment A:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // Use the Kotlin extension in the fragment-ktx artifact.
    setFragmentResultListener("requestKey") { requestKey, bundle ->
        // We use a String here, but any type that can be put in a Bundle is supported.
        val result = bundle.getString("bundleKey")
        // Do something with the result.
    } }


Fragment B (or DialogFragment):

button.setOnClickListener {
    val result = "result"
    // Use the Kotlin extension in the fragment-ktx artifact.
    setFragmentResult("requestKey", bundleOf("bundleKey" to result))
}

check official doc:https://developer.android.com/guide/fragments/communicate#fragment-result

Descombes answered 24/5 at 9:38 Comment(0)
S
0

What you want, according to Android Developers...

Sidon answered 27/4, 2016 at 12:46 Comment(0)
F
0

This method ensures that the calling fragment implements the onChangeListener of the dialog.

FragmentA (calling fragment):

MyDialogFragment f = new MyDialogFragment();
Bundle args = new Bundle();
args.putString("data", data);
f.setArguments(args);
// Set the calling fragment for this dialog.
f.setTargetFragment(FragmentA.this, 0);
f.show(getActivity().getSupportFragmentManager(), "MyDialogFragment");

MyDialogFragment:

import android.support.v4.app.DialogFragment;

public class MyDialogFragment extends DialogFragment {
    public OnChangeListener onChangeListener;

    interface OnChangeListener{
        void onChange(Data data);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Get the calling fragment and ensure that it implements onChangeListener.
        try {
            onChangeListener = (OnChangeListener) getTargetFragment();
        } catch (ClassCastException e) {
            throw new ClassCastException(
                "The calling Fragment must implement MyDialogFragment.onChangeListener");
        }
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        .....
        builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // Send the data to the calling fragment.
                onChangeListener.onChange(data);
            }
        });
        .....
    }
}
Florin answered 18/8, 2018 at 20:32 Comment(0)
B
0

dialogFragment.setTargetFragment is deprecated, see : doc

Instead of using a target fragment to pass results, the fragment requesting a result should use FragmentManager.setFragmentResultListener(String, LifecycleOwner, FragmentResultListener) to register a FragmentResultListener with a requestKey using its parent fragment manager. The fragment delivering a result should then call FragmentManager.setFragmentResult(String, Bundle) using the same requestKey. Consider using setArguments to pass the requestKey if you need to support dynamic request keys.

Here is a simple implementation :

  • Call from host Fragment

          val dialog = MockDialog.newInstance(
              "requestKey")
    
          dialog.show(
              childFragmentManager, MockDialog.TAG
          )
    
  • In MockDialog (which extends DialogFragment):

      dialog.setPositiveButton(R.string.dialog_yes) { _, _ ->
          parentFragmentManager.setFragmentResult(
              arguments!!.getString(DIALOG_REQUEST_PARAM)!!,// which is "requestKey"
              //add data to bundle
              bundleOf("result" to "any data")
          )
      }
    
  • Get result on host Fragment:

          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              childFragmentManager.setFragmentResultListener(
                  "requestKey", this
              ) { requestKey, result ->
                  // you data here 
                  val data = result.getString("result", null)
              }
          }
    

Base-line : you need to pass your "requestKey" and pass it back to host-fragment

Good luck,'.

Beaubeauchamp answered 5/4, 2022 at 21:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.