Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use SavedStateHandle and navigation Safe Args

I have two options to pass data between fragment, the navigation's safe args and viewModel's SavedStateHandle, what's the difference between them and how to use them in the correct place?

like image 957
ccd Avatar asked Sep 05 '20 09:09

ccd


People also ask

What is Androidx navigation?

Navigation is a framework for navigating between 'destinations' within an Android application that provides a consistent API whether destinations are implemented as Fragments, Activities, or other components. Latest Update. Stable Release. Release Candidate. Beta Release.

What are safe args?

Use Safe Args to pass data with type safety. The Navigation component has a Gradle plugin called Safe Args that generates simple object and builder classes for type-safe navigation and access to any associated arguments. Safe Args is strongly recommended for navigating and passing data, because it ensures type-safety.


2 Answers

There are few discussions about this issue. android ViewModelFactory with hilt https://issuetracker.google.com/issues/136967621

For me, most obvious solution is to use something like

SafeArgs.fromSavedStateHandle(savedStateHandle)

But for now, I am using string keys.

like image 181
akelix Avatar answered Oct 21 '22 02:10

akelix


If you are using hilt you can wrap the incoming arguments in the fragment (and other components) like so

open class BaseFragment : Fragment() { // Inherit your fragment from this

    override fun setArguments(args: Bundle?) {
        if (args != null) {
            if (args.getBundle(BUNDLE_ARGS) != null) {
                super.setArguments(args)
            } else {
                super.setArguments(Bundle(args).apply {
                    putBundle(BUNDLE_ARGS, args) // Wrap the arguments as BUNDLE_ARGS
                })
            }
        } else {
            super.setArguments(null)
        }
    }
}

and then for the view model, you can inherit from something like that

open class ArgsViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {

    val arguments get() = savedStateHandle.get<Bundle>(BUNDLE_ARGS)

    @MainThread
    inline fun <reified Args : NavArgs> navArgs() = NavArgsLazy(Args::class) {
        arguments ?: throw IllegalStateException("ViewModel $this has null arguments")
    }
}

And then use it just like you would use safe args

class FooViewModel @ViewModelInject constructor(
    @Assisted savedStateHandle: SavedStateHandle
) : ArgsViewModel(savedStateHandle) {

    private val args: FooFragmentArgs by navArgs()
}
like image 43
Aleksandr Belkin Avatar answered Oct 21 '22 03:10

Aleksandr Belkin