23

I am Using Navigation Drawer in my app. I have one MainActivity and rest of are Fragments. So the issue is Suppose i have three fragments like A,B,C.

Now in A i have one button and i am sending data from A>B.
For example putSring("datafrom A","datafrom A");
Now in B i receive data From A.
I have one button in B,and i am sending data from B>C.
For example putSring("datafrom B","datafrom B");
Now in C i receive data From B.
Then, I have one Button in C,and sending data from C>B.
For example putSring("datafrom C","datafrom C");

So,seems like in B i am getting data from two different fragments. I tried with all using activity and it work well with startActivityforresult. but how can i manager when all are fragments.

CodePlay
  • 1,914
  • 14
  • 20
chris
  • 699
  • 4
  • 12
  • 35
  • While u are sending data from A->B , than u have to manitain the BOOLEAN that i am from A and same case C->A , u have to use the same BOOLEAN that specify that u are from c and sending data to B – Ravindra Kushwaha Mar 10 '17 at 06:24
  • but how will i check? from which fragment it is passed – chris Mar 10 '17 at 06:25
  • While u are send data from A->B use the BOOLEAN value TRUE.....And when u are sending data from C->A , use the BOOLEAN value FALSE – Ravindra Kushwaha Mar 10 '17 at 06:28
  • but when you pass data from A>B on that time app will crash with NPE. reasone will it wont get false of C>B ..got it? – chris Mar 10 '17 at 06:30
  • If only one fragment is active at a time, _seems like in B i am getting data from two different fragments_ is impossible. Furthermore, if you use `setArguments()` on `Fragment` objects, you dont have to worry about that. – Talha Mar 10 '17 at 06:37
  • @chris Check my below solution, and let me know in case of concern – Ravindra Kushwaha Mar 10 '17 at 06:38
  • If some is looking for an answer in 2021 for Navigation Component: Check out https://stackoverflow.com/a/61239011/3209170 – HBB20 Jul 16 '21 at 20:05

3 Answers3

71

UPDATE

Starting with Androidx Activity 1.2.0-alpha02 and Androidx Fragment 1.3.0-alpha4, the official Android developer guide recommends to use the Activity/Fragment Result APIs over the deprecated Activity.onActivityResult(int, int, Intent) and Fragment.setTargetFragment(Fragment, int) methods:

it is strongly recommended to use the Activity Result APIs introduced in AndroidX Activity 1.2.0-alpha02 and Fragment 1.3.0-alpha02.

Thus, to pass data back to fragment B from C, call setFragmentResultListener() on fragment B's FragmentManager, as shown in the following example:

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
     }
}

In fragment C, set the result on the same FragmentManager by using the same requestKey using the setFragmentResult() API. Example:

setFragmentResult("requestKey", bundleOf("bundleKey" to "result"))

More details can be found at this guide.


The below answer is deprecated

You may call setTargetFragment() when you start the Fragment C from B. Example:

FragmentC fragmentC = FragmentC.newInstance();
fragmentC.setTargetFragment(FragmentB.this, REQUEST_CODE);
getFragmentManager().beginTransaction().replace(R.id.container, fragmentC).commit();

and then when you want to pass data back to fragment B from C, you can call the following code:

getTargetFragment().onActivityResult(
                getTargetRequestCode(),
                Activity.RESULT_OK,
                new Intent().putExtra("datafrom C", "datafrom C")
);

and get it from the onActivityResult() method in your fragment B:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode==REQUEST_CODE && resultCode==Activity.RESULT_OK) {
        String datafromC = data.getStringExtra("datafrom C");   
    }
}
CodePlay
  • 1,914
  • 14
  • 20
  • can not resolve newInstance() and can not resolve REQUEST_CODE – chris Mar 10 '17 at 06:34
  • newInstance() is a method which I always use to init the fragment, you may call FragmentC fragmentC = new FragmentC(); instead. – CodePlay Mar 10 '17 at 06:36
  • The REQUEST_CODE is a constant integer, which to let you to identify which fragment is triggered the onActivityResult() method, you may just assign an integer to it, if fragment C is the only fragment that passes data back to your fragment B. E.g. fragmentC.setTargetFragment(FragmentB.this, 1); and then check requestCode==1 in the fragment B's onActivityResult() method. – CodePlay Mar 10 '17 at 06:38
  • 6
    Such a neat, simple and native way. Yet it seems that loads of people are unaware about it – Kirill Starostin Aug 21 '18 at 11:40
  • 2
    @KirillStarostin what exactly is neat about manually calling on**Activity**Result? – Tim Nov 21 '18 at 11:24
5

When u are sending the data from Fragment A to Fragment B use the same boolean like below:-

FragmentA -> FragmentB

FragmentB ldf = new FragmentB ();
Bundle args = new Bundle();
args.putBoolean("BOOLEAN_VALUE",true);
ldf.setArguments(args);

getFragmentManager().beginTransaction().add(R.id.container, ldf).commit();

And when u are send data from Fragment C to Fragment B use the same BOOLEAN which is used in Fragment A to B like below-

FragmentC -> FragmentB

FragmentB ldf = new FragmentB ();
    Bundle args = new Bundle();
    args.putBoolean("BOOLEAN_VALUE",false);
    ldf.setArguments(args);

    getFragmentManager().beginTransaction().add(R.id.container, ldf).commit();

And in the last we have to check that value is recevied in FragmentB is from where like Fragment A OR FragemntC

FragmentB

   Boolean getValue= getArguments().getBoolean("BOOLEAN_VALUE");  
   if(getValue)
   {
    //VALUE RECEIVED FROM FRAGMENT A
   }
   else
   {
   //VALUE RECEIVED FROM FRAGMENT C
   }
Ravindra Kushwaha
  • 7,846
  • 14
  • 53
  • 103
4

Things changed a lot since 2017. The answer I post is basically an example from https://developer.android.com and it presents a good solution where your fragments, in any number, do not know anything about each other and still you are able to create a simple and elegant mechanism that can be used without much struggle.

The answer is based on ViewModels and LiveData.

Note: If you are not familiar with Architecture Components I strongly advise you to learn about it as much as you can any time you can as it will increase your production speed and decrease the number of errors in your projects.

Everything below is a citation from the following link: source (Kotlin/Java)

Share data between fragments

It's very common that two or more fragments in an activity need to communicate with each other. Imagine a common case of master-detail fragments, where you have a fragment in which the user selects an item from a list and another fragment that displays the contents of the selected item. This case is never trivial as both fragments need to define some interface description, and the owner activity must bind the two together. In addition, both fragments must handle the scenario where the other fragment is not yet created or visible.

This common pain point can be addressed by using ViewModel objects. These fragments can share a ViewModel using their activity scope to handle this communication, as illustrated by the following sample code:

class SharedViewModel : ViewModel() {
    val selected = MutableLiveData<Item>()

    fun select(item: Item) {
        selected.value = item
    }
}

class MasterFragment : Fragment() {

    private lateinit var itemSelector: Selector

    // Use the 'by activityViewModels()' Kotlin property delegate
    // from the fragment-ktx artifact
    private val model: SharedViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        itemSelector.setOnClickListener { item ->
            // Update the UI
        }
    }
}

class DetailFragment : Fragment() {

    // Use the 'by activityViewModels()' Kotlin property delegate
    // from the fragment-ktx artifact
    private val model: SharedViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        model.selected.observe(viewLifecycleOwner, Observer<Item> { item ->
            // Update the UI
        })
    }
}

Notice that both fragments retrieve the activity that contains them. That way, when the fragments each get the ViewModelProvider, they receive the same SharedViewModel instance, which is scoped to this activity.

This approach offers the following benefits:

  • The activity does not need to do anything, or know anything about this communication.
  • Fragments don't need to know about each other besides the SharedViewModel contract. If one of the fragments disappears, the other one keeps working as usual.
  • Each fragment has its own lifecycle, and is not affected by the lifecycle of the other one. If one fragment replaces the other one, the UI continues to work without any problems.
Jenea Vranceanu
  • 4,530
  • 2
  • 18
  • 34