22

I found the question but does not have solution in code

I want to have data when backpress/manual back happens. I am using navigateUp() to go back. How can I pass data to previous fragment? navigateUp() does not have any facility to pass data to previous fragment. Even I did not find solution using Safe Args. It's passing data forward. I want to have in backward Frad B -> Frag A.

My code to go back to previous fragment

Navigation.findNavController(view).navigateUp()

enter image description here

My question is, How can i get data in previous fragment. I can navigate to Frag A from Frag B using

Bhavesh Hirpara
  • 22,255
  • 15
  • 63
  • 104

6 Answers6

11

According to developer.android.com, you can use common for fragments where you want to share data ViewModel using their activity scope.

Here are steps:

  1. Create view model which will keep the data:
class SharedViewModel : ViewModel() {
    val dataToShare = MutableLiveData<String>()

    fun updateData(data: String) {
        dataToShare.value = data
    }
}
  1. Observe data changes in Fragment1:
class Fragment1 : Fragment() {

    private lateinit var viewModel: SharedViewModel

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewModel = ViewModelProviders.of(activity!!).get(SharedViewModel::class.java)
        viewModel.dataToShare.observe(this, Observer<String> { dataFromFragment2 ->
            // do something with data
        })
    }
}
  1. Update data in Fragment2 and if you're handling navigation properly, now, you should be able to receive data changes on Fragment1:
class Fragment2 : Fragment() {

    private lateinit var viewModel: SharedViewModel

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewModel = ViewModelProviders.of(activity!!).get(SharedViewModel::class.java)

        updateDataButton.setOnClickListener { v ->
            viewModel.updateData("New data for fragment1")
        }
    }
}

I hope answer helps.

valerybodak
  • 4,195
  • 2
  • 42
  • 53
Natig Babayev
  • 3,128
  • 15
  • 23
  • 10
    Sharing ViewModel between Fragment will add complexity to the source code. – Harvey Dec 25 '19 at 09:16
  • @Natig if I use SharedViewModel then I will have 2 viewModels in a fragment ? in FragmentA, I will have FragmentAViewModel and SharedViewModel, and in FragmentB, I will have FragmentBViewModel and SharedViewModel ? so the the shared view model only to pass the data back to previous fragment ? – sarah Mar 31 '20 at 07:50
  • @Natig or I just need to make make one viewmodel (SharedViewModel) for my two fragments ? I am confused. sorry I am a beginner – sarah Mar 31 '20 at 07:57
  • Thats why they have given support for shared view model guys – Cyph3rCod3r Sep 15 '20 at 10:17
  • If you don't want to have 2 viewmodels (or a shared one) then think about the problem for one minute and come to the realization the problem is not the number of viewModels, is that the data you want to store, outlives both, and so it should be stored in a third place (repository?) and each fragment (and its different view models) should use the same repository to fetch the data. That is the "correct" (for 2021) approach I would have thought if this sharing was important. Alternatively, you can use the fragment result listener if data fits in a bundle/intent. – Martin Marconcini Jul 13 '21 at 08:06
7

You can use NavigationResult library. Basically it's startActivityForResult but for Fragments in Navigation component.

Mahdi Nouri
  • 1,391
  • 14
  • 29
5

Please use the OFFICIAL androidx's components. setFragmentResultListener() and setFragmentResult() methods:

implementation "androidx.fragment:fragment-ktx:1.3.5"

Cheers ;)

valerybodak
  • 4,195
  • 2
  • 42
  • 53
1

To pop destinations when navigating from one destination to another, add an app:popUpTo attribute to the associated <action> element. To navigate from fargment2 to Fragment1 with arguments, specify in the navigation graph the action of the caller fragment and the arguments of the destination fragment :

<fragment
    android:id="@+id/fragment2"
    android:name="com.example.myapplication.Fragment2"
    android:label="fragment_2"
    tools:layout="@layout/fragment_2">

    <action
        android:id="@+id/action_2_to_1"
        app:destination="@id/fragment1"
        app:popUpTo="@+id/fragment1"/>
</fragment>
<fragment
    android:id="@+id/fragment1"
    android:name="com.example.myapplication.Fragment1"
    android:label="fragment_1"
    tools:layout="@layout/fragment_1">

        <argument
            android:name="someArgument"
            app:argType="string"
            app:nullable="false"
            android:defaultValue="Hello Word"/>
</fragment>

In your Fragment2 class, you call your action and pass your argument:

   val action = Fragment2Directions.action2To1("MY_STRING_ARGUMENT")
        findNavController().navigate(action)
Meriam
  • 945
  • 8
  • 18
0

You should use static variables/companion objects, because it is better than shared viewmodel as it is not simple/nice architecture. As it it not straightforward, I think it is the best way.

To navigateUp From FragmentB to FragmentA

FragmentB:

isBackpressed = true
findNavController().navigateUp() 

FragmentA:

onViewCreated() {
    // todo
    if(isBackpressed) {
         isBackpressed = false
         // do whatever you want
    }
}
Khamidjon Khamidov
  • 6,783
  • 6
  • 31
  • 62
-4

You can just call

findNavController().navigate(R.id.fragment1, args)

where args is your bundle. In fragment1, fetch the data from the arguments

P.Rai
  • 1
  • 2