Pass data/bundle using navigateUp in Android Navigation Component
Asked Answered
C

6

23

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

Catabasis answered 8/3, 2019 at 7:37 Comment(6)
2nd solution is singleton java. companion object in kotlinCatabasis
Did you find any solution?Daryl
I have used companion objectCatabasis
I hope Android team soon will provide simple and convenient solution for this simple action.Nonet
Hi! Could you please post your solution @BhaveshHirpara?Kella
Please see my answer using official androidx components - https://mcmap.net/q/190422/-pass-data-bundle-using-navigateup-in-android-navigation-componentSiouan
W
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.

Wilkison answered 8/3, 2019 at 10:8 Comment(5)
Sharing ViewModel between Fragment will add complexity to the source code.Patois
@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 ?Nonet
@Natig or I just need to make make one viewmodel (SharedViewModel) for my two fragments ? I am confused. sorry I am a beginnerNonet
Thats why they have given support for shared view model guysDuello
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.Romanaromanas
S
8

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

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

Cheers ;)

Siouan answered 14/5, 2021 at 7:5 Comment(0)
G
7

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

Genvieve answered 24/5, 2019 at 18:51 Comment(3)
this is way too invasive even for a simple project.Peplum
@Alberto That's why we need to use the official Android's approach - https://mcmap.net/q/190422/-pass-data-bundle-using-navigateup-in-android-navigation-componentSiouan
I wasn't aware of that, I'll check it out!Peplum
W
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)
Wilkens answered 18/10, 2020 at 17:12 Comment(0)
T
-1

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
    }
}
Titanomachy answered 5/9, 2020 at 9:55 Comment(1)
this is a very bad practice. Also static variables wont survive configuration changes.Stokeontrent
D
-4

You can just call

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

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

Diastase answered 26/11, 2019 at 10:36 Comment(4)
is this creating new fragment or is it navigating up? I want to backCatabasis
@BhaveshHirpara Please see my answer here: https://mcmap.net/q/190422/-pass-data-bundle-using-navigateup-in-android-navigation-componentSiouan
navigateUp() and navigate do two differents actions, This is not a good answerDebbiedebbra
This will just instantiate the fragment1 againUndulate

© 2022 - 2024 — McMap. All rights reserved.