Inject runtime parameters with Dagger-Hilt
Since Hilt appeared to make it easier the dependency injection in Android, it was impossible to inject runtime parameters without using third party libraries. Since Dagger version 2.31, exists the @AssistedInject
annotation. With this annotation we can instruct Dagger-Hilt what dependencies need to be created at runtime and delay the injection of this parameters until we can provide those values.
This is necessary to inject parameters into ViewModel constructor and be able to execute some code in the init
function. It can be an external API call or some query to our local database.
In this post we will learn how to use @AssistedInject
from Dagger to inject runtime parameters to ViewModels with Hilt.
Installation
In the root project build.gradle
file, we will include the Hilt classpath:
|
|
Once we have Hilt classpath we will add Hilt plugin to build.gradle
file from app module.
|
|
And the next lines to our dependencies block:
|
|
We should keep in mind that we need
kapt
plugin on ourbuild.gradle
. For this we will add this line with the rest of plugins in ourbuild.gradle
from app module:
|
|
Those were the needed dependencies to make Hilt work in our project. In this post we will use libraries that are not defined here.
In this link you can see the complete build.gradle
file: app/build.gradle
Implementation
For this example we will be using a repository class with a function which receives a name and returns a welcome message. To acomplish this we will create the interface below:
|
|
And it’s implementation:
|
|
We should annotate the constructor with @Inject
so we can declare a @Binds
annotation in the Hilt module to be able to inject the implementation when we call an interface of type UserRepository.
Next we will create our ViewModel
, this class will receive the user name from the Activity
or Fragment
and call the repository to get the welcome message:
|
|
In this ViewModel
we can see how we should annotate the constructor with @AssistedInject
so Dagger-Hilt knows this class has dependencies that will be injected at runtime. This runtime dependencies will be annotated with @Assisted
.
To be able to create our ViewModel
with the extension by viewModels()
from AndroidX library, we should create the Factory
class wich will be provided to the extension:
|
|
You can see we need an interface called UserViewModelAssistedFactory
. This interface will handle the runtime parameters injected to the ViewModel
:
|
|
It’s an interface with a create
function. This function receive all the runtime parameters we want to inject in our ViewModel. In this example we only need a name
parameter, but in case we need more parameters injected at runtime, they will be provided to this function.
With this we are able to complete our ViewModel with the logic to get the answer from the repository and expose it to the Fragment
or Activity
through a StateFlow.
The complete ViewModel
:
|
|
Related to Hilt
we only have to create the module to handle the creation of dependencies. For this example we will be using this module:
|
|
In this module we declare a function to provide a Dispatcher
so it will be easier to test this ViewModel in a future. We declare a @Binds
function so when we inject a UserRepository
interface Hilt provides its implementation UserRepositoryImpl
.
Now we can user our ViewModel in Activities
or Fragments
:
|
|
We need to @Inject
the AssistedFactory and use the UserViewModel.Factory to create our ViewModel
.
From this step we only need to observe changes in the ViewModel StateFlow to be able to update our UI. This can be done in Fragments
observing from the onViewCreated
.
|
|
Remember you need a class extending Application annotated with
@HiltAndroidApp
and each Activity or Fragment that uses injection with Hilt need to be annotated with@AndroidEntryPoint
.
Conclusion
Now we can inject Runtime values with Dagger @AssistedInject
in a simple way and we can keep using navArgs
from AndroidX.
You can see the complete example in this repository: HiltAssistedInject