28

I have Two fragment. SecondFragment and ThirdFragment. Actually I use the Navigation Component for passing value between fragments. Like this:

SecondFragment:

val action = SecondFragmentDirections.action_secondFragment_to_thirdFragment().setValue(1)

Navigation.findNavController(it).navigate(action)

Here is how I read the value from the ThirdFragment:

 arguments?.let {
           val args = ThirdFragmentArgs.fromBundle(it)
           thirdTextView.text = args.value.toString()
       }

It's work fine. Now my stack is look like this:

ThirdFragment

SecondFragment 

There is any option for pass value from the opened ThirdFragment to the previous SecondFragment with the new Navigation Component? (When ThirdFragment is finishing)

I know about onActivityResult, but If Nav.Component serve better solution than I want use that.

Thank you!

RKRK
  • 1,284
  • 5
  • 14
  • 18
vihkat
  • 895
  • 3
  • 13
  • 28

4 Answers4

35

It's a bit late for this answer but someone may find it useful. In the updated versions of the navigation component library it is now possible to pass data while navigating back.

Suppose the stack is like this

FragmentA --> FragmentB.

We are currently now in FragmentB and we want to pass data when we go back to FragmentA.

Inside FragmentAwe can create an observer with a key:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val navController = findNavController()
// Instead of String any types of data can be used
navController.currentBackStackEntry?.savedStateHandle?.getLiveData<String>("key")
    ?.observe(viewLifecycleOwner) { 

    }
}

Then inside FragmentB if we change its value by accessing previous back stack entry it will be propagated to FragmentA and observer will be notified.

val navController = findNavController()
navController.previousBackStackEntry?.savedStateHandle?.set("key", "value that needs to be passed")
navController.popBackStack()
Alif Hasnain
  • 1,176
  • 1
  • 11
  • 24
  • 1
    While I agree that this feels a bit hacky, it's actually the official way of doing this. https://developer.android.com/guide/navigation/navigation-programmatic#returning_a_result – Praxder May 11 '21 at 21:31
  • sometimes navController.popBackStack() fragment is not getting popped up – Richa Dec 13 '21 at 15:35
14

Just came across setFragmentResult(), pretty easy to use. The docs on this are here.

If you are navigating: Fragment A -> Fragment B -> Fragment A Add this to fragment A:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setFragmentResultListener("requestKey") { requestKey, bundle ->
        shouldUpdate = bundle.getBoolean("bundleKey")
    }
}

Then in fragment B add this line of code:

setFragmentResult("requestKey", bundleOf("bundleKey" to "value to pass back"))
// navigate back toFragment A

When you navigate back to fragment A the listener will trigger and you'll be able to get the data in the bundle out.

Al Rosenthal
  • 149
  • 1
  • 5
0

What you are asking for is an anti-pattern. You should either

  • navigate to the second fragment again with the new values you would like to set

  • use the third fragment ins a separate activity and start it with startActivityForResult()

  • use a ViewModel or some kind of singleton pattern to hold on to your data (make sure you clear the data after you no longer need it)

these are some of the patterns that came to my mind. Hope it helps.

Kayvan N
  • 8,108
  • 6
  • 29
  • 38
  • In some cases your solutions don't work. In my case, there is a fragment that should return the results to its previous fragment , and the previous fragment may be different each time. just like startActivityForResult – Nabzi Feb 17 '20 at 09:49
  • 13
    "What you are asking for is an anti-pattern." Define anti-pattern. I find using ViewModel for transition an anti-pattern. Why is an activity finishing with a result is not an anti-pattern, but finishing a fragment with a result an anti-pattern? – funct7 Feb 22 '20 at 00:15
  • 1
    solution is here - https://github.com/PHELAT/NavigationResult Now you can send data back to previous fragment. It's just - startActivityForResult but for fragments! (Addon for Jetpack's Navigation component). – Avinash Sharma Jun 27 '20 at 20:27
  • > use the third fragment ins a separate activity. Isn't that supposed to be Single activity application? – Mahendran Nov 06 '20 at 10:31
  • Anti-pattern is a word that should be erased from the programmer lexicon. There is no "anti-pattern" just consensus/conflicting paradigms. [Finite-state_machine](https://en.wikipedia.org/wiki/Finite-state_machine) This paradigm goes in accordance with state transitions in a State Machine pattern. – Delark May 02 '23 at 22:35
-1

As described here:

When navigating using an action, you can optionally pop additional destinations off of the back stack. For example, if your app has an initial login flow, once a user has logged in, you should pop all of the login-related destinations off of the back stack so that the Back button doesn't take users back into the login flow.

To pop destinations when navigating from one destination to another, add an app:popUpTo attribute to the associated element. app:popUpTo tells the Navigation library to pop some destinations off of the back stack as part of the call to navigate(). The attribute value is the ID of the most recent destination that should remain on the stack.

<fragment
    android:id="@+id/c"
    android:name="com.example.myapplication.C"
    android:label="fragment_c"
    tools:layout="@layout/fragment_c">

    <action
        android:id="@+id/action_c_to_a"
        app:destination="@id/a"
        app:popUpTo="@+id/a"
        app:popUpToInclusive="true"/>
</fragment>
Morteza Rastgoo
  • 6,772
  • 7
  • 40
  • 61