Portal Berita dan Informasi Terbaik di Indonesia

Passing Safe Args to your ViewModel with Hilt | by Matt Robertson

UPDATED for Hilt 2.31, which supports injecting ViewModels.

Hilt has been a fantastic addition to the Android Jetpack libraries, greatly simplifying the beast that is Dagger for Android. Injecting Activities and Fragments is easy with @AndroidEntryPoint.

@AndroidEntryPoint
class UserFragment: Fragment()

As of Hilt 2.31 it is just as easy to inject ViewModels.

class UserViewModel @Inject constructor (
private val repo: UserRepo
) : ViewModel() {
...
}

Add in the magic of Kotlin delegates and we have an incredibly simple way to obtain a ViewModel with all of its dependencies (once you have set up your Hilt bindings).

val viewModel: UserViewModel by viewModels()

But what if we need to pass a Safe Args argument like a userId to our ViewModel? Without dependency injection, we would instantiate a ViewModelFactory using our userId and provide this ViewModelFactory to our delegate.

val args: UserFragmentArgs by navArgs()val viewModelFactory: UserViewModelFactory by lazy {
UserViewModelFactory(args.userId)
}
val viewModel: UserViewModel by viewModels { viewModelFactory }

But by using Hilt, we have intentionally shifted the responsibility of dependency management away from our Fragment. It would be counter-productive to include ViewModelFactory instantiation logic here now. So how do we pass a Safe Args argument to a ViewModel instance obtained via Hilt?

The answer is found in SavedStateHandle. SavedStateHandle is “a key-value map that lets you write and retrieve objects to and from the saved state. These values persist after the process is killed by the system and remain available through the same object.” Persisting state beyond process death is a useful enough feature on its own, but in our Hilt-SafeArgs-ViewModel setup this library becomes even more powerful. To use SavedStateHandle we simply include it in our ViewModel constructor.

class UserViewModel @Inject constructor (
private val repo: UserRepo,
private val state: SavedStateHandle
) : ViewModel() {
...
}

Now that we have all the pieces in place, what do we need to do to pass our Safe Args argument to our ViewModel? The answer might surprise you: nothing. Our userId Safe Arg is already available to our ViewModel via the SavedStateHandle without any additional work.

class UserViewModel @Inject constructor (
private val repo: UserRepo,
private val state: SavedStateHandle
) : ViewModel() {
val user = repo.getUser(
state.get<String>("userId")
)
}

Just be sure to use the same key name with SavedStateHandle that you would have used from your Safe Args. For example, to use our Safe Args argument in our Fragment we would retrieve it like such:

val args: UserFragmentArgs by navArgs()
...
args.userId

Note that the Safe Args argument name args.userId is the name that we used as the SavedStateHandle key in our ViewModel (“userId”). The Safe Args library passes its content in such a way that it is automatically available from the SavedStateHandle that Hilt provides for you.

That’s it! It feels a bit like magic, and it’s a fantastic addition by the Jetpack teams who worked on these libraries.

Follow for more on best practices in Kotlin and Android development.



Source by [author_name]

Leave a Reply

Your email address will not be published.