Creating ViewModel dependencies using Hilt
In the previous blog, we read about how we can create the network module, and how we inject dependencies related to network connections using Hilt.
You can jump to the previous blogs from here
ApiClient Interface
@JvmSuppressWildcards
interface ApiClient {
@POST("<Your endpoint here>")
suspend fun loginUsingCredentials(@Body requestBody: RequestBody): Token
}
In the above code block, we create a simple interface class, and a suspend function that will fetch us the authentication token from the server. You can read about suspend functions here.
Next, we will add some code to inject dependencies for our ViewModel.
VMFactory
First, start by creating a new class and naming it VMFactory.
@Singleton
class VMFactory @Inject constructor(private val viewModels: MutableMap<Class<out ViewModel>, Provider<ViewModel>>) :
ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T = viewModels[modelClass]?.get() as T
}
This is just a factory method that will be used to create instances of our ViewModel classes. You can see that this method has a mutable map and Provider as dependencies.
VMKey
We now create a VMKey annotation. This would be the only time we create a java file to be used.
@MapKey
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface VMKey {
Class<? extends ViewModel> value();
}
Do remember to select Annotation when you create the new java file.
This annotation will be used to specify the key in the mutable map, the dependency of the VMFactory.
And at last, we create our VMModule.
VMModule
This module will contain all our ViewModels, and inject them along with their required dependencies.
@Module
@InstallIn(ApplicationComponent::class)
abstract class VMModule {
@Binds
internal abstract fun bindVMFactory(factory: VMFactory): ViewModelProvider.Factory
@Binds
@IntoMap
@VMKey(AuthViewModel::class)
abstract fun authViewModel(authViewModel: AuthViewModel): ViewModel
}
As you can see, we add our VMFactory in this module, so that it can be used to inject the ViewModels.
Below that, we add our AuthViewModel, which is just a ViewModel class for the authentication package. You can replace this with your ViewModel class(es).
Viola, we are done. This is all you need to do to inject your network dependencies using Hilt.
Some code examples you can use to create the repo and ViewModel classes.
Code for the Repo class.
class AuthRepo @Inject constructor(private val apiClient: ApiClient) {
// Add code for the repo methods}
Code for the VM class
class AuthViewModel @Inject constructor(private val authRepo: AuthRepo): ViewModel() {// Add code for Viewmodel methods
}
Finally, this is how we instantiate a ViewModel class, inside our Fragment or Activity.
private val authViewModel by viewModels<AuthViewModel> { vMFactory }
In the above code block, vMFactory is injected inside the BaseFragment, this is how we do that
@Inject
lateinit var viewModelFactory: ViewModelFactory
And Hilt takes care of the rest.
In the last three blogs, we read about how we inject our Network and ViewModel dependencies using Hilt, which lets us have a clean code using a defined architecture like MVVM.