Android jetpack navigation component result from d

2020-07-09 09:49发布

So far I'm successfully able to navigate to dialogs and back using only navigation component. The problem is that, I have to do some stuff in dialog and return result to the fragment where dialog was called from.

One way is to use shared viewmodel. But for that I have to use .of(activity) which leaves my app with a singleton taking up memory, even when I no longer need it.

Another way is to override show(fragmentManager, id) method, get access to fragment manager and from it, access to previous fragment, which could then be set as targetfragment. I've used targetFragment approach before where I would implement a callback interface, so my dialog could notify targetFragment about result. But in navigation component approach it feels hacky and might stop working at one point or another.

Any other ways to do what I want? Maybe there's a way to fix issue on first approach?

2条回答
家丑人穷心不美
2楼-- · 2020-07-09 10:28

In Navigation 2.3.0-alpha02 and higher, NavBackStackEntry gives access to a SavedStateHandle. A SavedStateHandle is a key-value map that can be used to store and retrieve data. These values persist through process death, including configuration changes, and remain available through the same object. By using the given SavedStateHandle, you can access and pass data between destinations. This is especially useful as a mechanism to get data back from a destination after it is popped off the stack.

To pass data back to Destination A from Destination B, first set up Destination A to listen for a result on its SavedStateHandle. To do so, retrieve the NavBackStackEntry by using the getCurrentBackStackEntry() API and then observe the LiveData provided by SavedStateHandle.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val navController = findNavController();
// We use a String here, but any type that can be put in a Bundle is supported
navController.currentBackStackEntry?.savedStateHandle?.getLiveData("key")?.observe(
    viewLifecycleOwner) { result ->
    // Do something with the result.
}

}

In Destination B, you must set the result on the SavedStateHandle of Destination A by using the getPreviousBackStackEntry() API.

navController.previousBackStackEntry?.savedStateHandle?.set("key", result)
查看更多
beautiful°
3楼-- · 2020-07-09 10:44

When you use Navigation Component with dialogs, this part of code looks not so good (for me it returned nothing)

navController.currentBackStackEntry?.savedStateHandle?.getLiveData("key")?.observe(
viewLifecycleOwner) { result ->
// Do something with the result.}

You need to try way from official docs and it help me a lot

This part is working for me:

 val navBackStackEntry = navController.getBackStackEntry(R.id.target_fragment_id)

    // Create observer and add it to the NavBackStackEntry's lifecycle
    val observer = LifecycleEventObserver { _, event ->
        if (event == Lifecycle.Event.ON_RESUME
            && navBackStackEntry.savedStateHandle.contains("key")
        ) {
            val result =
                navBackStackEntry.savedStateHandle.get<Boolean>("key")
            // Do something with the result

        }
    }
    navBackStackEntry.lifecycle.addObserver(observer)

    // As addObserver() does not automatically remove the observer, we
    // call removeObserver() manually when the view lifecycle is destroyed
    viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
        if (event == Lifecycle.Event.ON_DESTROY) {
            navBackStackEntry.lifecycle.removeObserver(observer)
        }
    })

And in your dialog:

navController.previousBackStackEntry?.savedStateHandle?.set(
            "key",
            true
        )
查看更多
登录 后发表回答