Introduction
- This series is not going to be in any particular order, so feel free to read whatever blog post you want. Anytime I find something that I think could use a blog post, I will write one and put it here
Getting started
- This post is not about understanding what a ViewModel is but more so the ViewModelProvider.Factory interface and why we use it. So a typical ViewModel class might look like something below:
class CalfViewModel(private val repository: CalfRepository): ViewModel() {
class CalfViewModelFactory(private val repository: CalfRepository): ViewModelProvider.Factory{
override fun <T:ViewModel> create(modelClass: Class<T>):T{
if(modelClass.isAssignableFrom(CalfViewModel::class.java)){
@Suppress("UNCHECKED_CAST")
return CalfViewModel(repository) as T
}
throw IllegalArgumentException("UNKNOWN VIEW MODEL CLASS")
}
}
- The code block is the ViewModel section from the Google code lab,HERE.
What is a ViewModel
- Now as the documentation so clearly states, The ViewModel class is designed to store and manage
UI-related data
in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations. The so calledUI-related data
is a few defferent kinds of data, such as, data the user enters, data generated during runtime and data loaded from a database.
ViewModelProvider.Factory
So why do we have to use a Factory interface at all? Can't we just pass some parameters into the primary constructor of the ViewModel and make it work? The answer to that is
NO!
as the documentation, HERE,states,You should never manually construct a ViewModel outside of a ViewModelProvider.Factory.
At this moment you are probably saying, but Tristan I have seen ViewModels being constructed with the ViewModelProvider class like this:
var viewModel = ViewModelProvider(this)
- Doesn't that contradict the documentation that stated
You should never manually construct a ViewModel outside of a ViewModelProvider.Factory.
? Actually it doesn't, according to the documentation, HERE,ViewModelProvider(this)
will use the default Factory interface.
Custom ViewModelProvider.Factory
- So we now know that a ViewModel should not be constructed outside of a ViewModelProvider.Factory. We also know a ViewModel with no properties inside of its primary constructor uses the default ViewModelProvider.Factory but what happens when we want to use a constructor with multiple properties? -The answer is we create a class that implements the ViewModelProvider.Factory interface and that is exactly what we have done:
class CalfViewModelFactory(private val repository: CalfRepository): ViewModelProvider.Factory
- Having a class implement the ViewModelProvider.Factory allows us to take advantage of polymorphism and use this class of instantiating a ViewModel. The create() method is nothing too fancy:
override fun <T:ViewModel> create(modelClass: Class<T>):T{
if(modelClass.isAssignableFrom(CalfViewModel::class.java)){
@Suppress("UNCHECKED_CAST")
return CalfViewModel(repository) as T
}
throw IllegalArgumentException("UNKNOWN VIEW MODEL CLASS")
}
- All we have to do is override the
create()
method, do some error handing and return an instance of the ViewModel class
What does ViewModelProvider.Factory actually do?
- Well as we know the Factory interface is what allows us to customize the ViewModel. However, it is actually the ViewModelProvider that scopes the ViewModel to the current lifecycle of the activity or fragment that it is bound to.
Conclusion
- Thank you for taking the time out of your day to read this blog post of mine. If you have any questions or concerns please comment below or reach out to me on Twitter.
Top comments (0)