3 ways to handle view model creation in Android with dagger and Kotlin
The library that we are going to talk about in this blog is ViewModel
from the official architecture component, dagger-android
for managing dependency injection. If you want to learn dagger-android
in a quick and easy way, I’ve got a blog covered.
Only one way for the creation
Even you use things like dagger
to handle dependencies, you need to know that you ALWAY use ViewModelProviders.of().get()
to get the instance of your view model. It will manage the life cycle of a view model for you.
With this in mind, let’s start.
Case 1: Get an instance of view model without extra parameter
This one is quite easy. You create this method in your BaseActivity
or BaseFragment
or Utils
.
1 | protected inline fun <reified T : ViewModel> getViewModel(): T = |
Then use it like this:
1 | val listViewModel: ListViewModel = getViewModel() |
The type T
will be inferred from the left side.
Case 2: Get an instance of view model with extra parameter
In this case, you need to create ListViewModel(val listStore:ListStore)
, but ListStore
is in dagger
, how you do that?
Well, first, we always use ViewProviders
to manage view model. So, we need to find another way to handle the customization phase of the view model, here we will inject a view model factory to do the trick.
Create the ViewModelFactory in a separate file:
1 | class ViewModelFactory<T : ViewModel> |
Then in your activity
or fragment
, create the ViewModelFactory and inject it.
1 | lateinit var viewModelFactory: ViewModelFactory<ListViewModel> |
Here, we only inject the ViewModelFactory
, not the ViewModel
.
Let’s say that your ViewModel
need a dependency named listStore
which is under dagger
‘s management. This is how you declare it:
1 | class ListViewModel |
You have to @inject
the dependencies from the constructor according to this line: @Inject lateinit var viewModelFactory: ViewModelFactory<ListViewModel>
. Because the constructor of ListViewModel
will be invoked during the injection
of the ViewModelFactory
.
Then, in your activity,
1 | val viewModel:ListViewModel = getViewModel(viewModelFactory) |
We can still re-use the getViewModel()
?! Of course, you can’t.
1 | protected inline fun <reified T : ViewModel> getViewModel( |
It’s a just another overload version of getViewModel()
That’s it.
Case 3: Creating a view model with custom parameters without using dagger’s injection
This case is for where your ViewModel
needs some dependencies which are not under dagger
‘s management. Something like this:
1 | class ListViewModel( |
The ListViewModel
needs to get listId
when it is initialized. How to do this?
First, we need a ViewModelFactory
:
1 | protected inline fun <VM : ViewModel> viewModelFactory(crossinline f: () -> VM) = |
It’s the same method as before with a slightly different signature.
And that famous getViewModel()
is back:
1 | protected inline fun <reified T : ViewModel> getViewModel(crossinline f:() -> T): T = |
Then you can use it like this:
1 | val listViewModel:ListViewModel = getViewModel { ListViewModel(listId) } |
End
That’s it. Now you get it. Hope it helps.
Follow me (albertgao) on twitter, if you want to hear more about my interesting ideas.
Thanks for reading!