androiddependency-injectionandroid-viewmodelandroid-jetpack-navigationdagger-hilt

How to use Hilt to inject a safe-args argument into a viewmodel?


I have found a similar question here. At the time of writing this question there is only this answer avaliable, which does not provide any help to me, and I believe also to the person who asked the question.

I checked the repo which is linked in the answer and it "solves" the problem by creating an init method in the viewmodel and calling it in the Activity/Fragment.

Since the viewmodel has already been injected, this solution does not seem like ideal to me, and I would like to know if there are other options available when using hilt.


Solution

  • As per this comment and the release of AndroidX Hilt 1.0.0-alpha03, Hilt has supported ViewModels that take a SavedStateHandle as a parameter (right alongside your other injected parameters).

    This SavedStateHandle is automatically, without you doing anything, populated with the arguments passed to your fragment (i.e., the same arguments you get from requireArguments() and the same arguments that are read by Safe Args).

    Therefore in your ViewModel's constructor, you can immediately access those arguments from the SavedStateHandle, without having to do any manual passing of arguments to your ViewModel.

    @HiltViewModel
    class MainViewModel @Inject constructor(
        val userDataManager: UserDataManager,
        savedStateHandle: SavedStateHandle
    ) : ViewModel() {
        init {
            // Use the same argName as in your navigation graph
            val yourArgument: String = savedStateHandle["argName"]
            // Now use that argument to load your data, etc.
        }
    }
    

    The feature request for Safe Args integration with SavedStateHandle is already fixed and will be part of the upcoming Navigation 2.4.0-alpha01 release. Once that is released, you'd be able to do something like MainFragmentArgs.fromSavedStateHandle(savedStateHandle) to get the same Args class you're currently able to get from by navArgs() within your ViewModel.