14

let sat I have some destinations like this

from fragment A --> to fragment B --> to fragment C

I can use Safe Args to pass data from fragment A to fragment B. and also using safe args from fragment B to fragment C.

what if I want to bring a string that generated in fragment C back to fragment B or to fragment A ?

to navigate from fragment C to fragment B, I use code:

Navigation.findNavController(fragmentView).navigateUp()

and to navigate from fragment C to fragment A, I use code:

Navigation.findNavController(view).popBackStack(R.id.fragmentA, false)

so how to pass a value back to previous fragment destination ? do I have to make an action back from fragment C to fragment B and pass the value through safe args ?

really need your help. Thank you very much :)

Alexa289
  • 8,089
  • 10
  • 74
  • 178
  • Did you tried using interfaces? – Vivek Singh Aug 18 '19 at 05:49
  • @VivekSingh to create some listener using interface ? – Alexa289 Aug 18 '19 at 05:51
  • if you make an action from C to A, then the B will still be in your back stack, same the C. – ghita Aug 18 '19 at 06:02
  • @ghita so what should I do ? do you ever have this problem ? – Alexa289 Aug 18 '19 at 06:21
  • i am still stuck with this problem, thinking of a solution... https://stackoverflow.com/questions/57536179/component-navigation-pop-from-backstack-with-arguments – ghita Aug 18 '19 at 06:28
  • @ghita maybe I will try to use listener, please inform me if there is an answer on your question there :) – Alexa289 Aug 18 '19 at 06:53
  • 1
    I have used popBackStack with SharedPrefs. I will post here if I will find a better solution. Please do the same if you find a better solution, thnx. – ghita Aug 18 '19 at 07:29
  • Possible duplicate of [Pass data/bundle using navigateUp in Android Navigation Component](https://stackoverflow.com/questions/55058689/pass-data-bundle-using-navigateup-in-android-navigation-component) – musooff Aug 19 '19 at 01:27

3 Answers3

20

You can use the below snippet for sending data to previous fragment.

Fragment A observing the data:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<String>("key")?.observe(viewLifecycleOwner) { data ->
        // Do something with the data.
    }
}

Fragment B sending the data:

findNavController().previousBackStackEntry?.savedStateHandle?.set("key", data)
findNavController().popBackStack()

I also wrote extensions for this.

fun <T : Any> Fragment.setBackStackData(key: String,data : T, doBack : Boolean = true) {
    findNavController().previousBackStackEntry?.savedStateHandle?.set(key, data)
    if(doBack)
    findNavController().popBackStack()
}

fun <T : Any> Fragment.getBackStackData(key: String, result: (T) -> (Unit)) {
    findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<T>(key)?.observe(viewLifecycleOwner) {
        result(it)
    }
}

Usage:

Fragment A:

getBackStackData<String>("key") { data ->
    // Do something with the data.
}

Fragment B:

setBackStackData("key",data)

    

Note: I am using String as data. You may use any other type of variable.

Note: If you are going to use a Class as data, don't forget to add @Parcelize annotation and extend Parcelable.

Amir
  • 1,628
  • 20
  • 28
  • perfect, if have result immediaetely replace ```.getLiveData("key")?.observe(viewLifecycleOwner) { data ->``` on ```.get("data")``` – Fortran May 11 '21 at 08:53
  • Can we send a state of a game (eg: pause) to previous fragment and show the same UI state when the fragment is launched again ? – Chandu Apr 25 '23 at 19:17
  • @Chandu Yes, you may send any data type. Just declare the data type and use it. ```enum class GameState {} ... setBackStackData("state",GameState.Paused) ... getBackStackData("state") ... ``` – Amir Apr 30 '23 at 10:16
  • above solution working flowless – Pankaj Jangid Aug 23 '23 at 12:59
0

i have just came across the same problem and have several options i can propose (currently considering myself which ones is best for my use case).

  1. create a navigation action from fragment C back to fragment A. note that if that's all you do, your stack will now be: A-B-C-A. to avoid this, you can use popUpTo and PopUpToInclusive. see the documentation.

the disadvantage of this method is that fragment A will be cleared no matter what, and would have to re-load (and fetch all its' data again).

  1. use a shared ViewModel between for your fragments, and observe the required value with LiveData. in this scenario, fragment C will update a LiveData value in the shared ViewModel, which fragment A observes. now when you go back to fragment A, your observer will be triggered with the value set by fragment C.

  2. similar to option 2, if you are using an external data source (like a Room database) you can observe changes using LiveData in fragment A. all fragment C has to do in this case is update the data source, and fragment A will automatically be updated through the LiveData

or_dvir
  • 479
  • 1
  • 7
  • 22
0

From Fragment version 1.3.0, you can use setFragmentResultListener and setFragmentResult to pass a value between two fragments

Mrm
  • 1
  • 1
  • 2
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 29 '23 at 15:59