Understanding the ViewModelProvider.Factory interface in Android with Kotlin
Tristan Elliott
Posted on June 8, 2022
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
GitHub version
- GitHub for code is HERE
Understanding the code
- So by the end of this tutorial we are going to be able to understand this code:
class CalfViewModelFactory(
private val calfDAO: CalfDAO
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if(modelClass.isAssignableFrom(CalfViewModel::class.java)){
return CalfViewModel(calfDAO) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
- Kotlin is great, Kotlin is awesome but it does have some wild looking syntax and lets break some of it down.
What is going on?
- If you are not familiar with what a ViewModel is, I highly suggest that you read THIS first and then return. The syntax of,
class CalfViewModelFactory(
private val calfDAO: CalfDAO
) : ViewModelProvider.Factory
- is the most normal looking.We use
class CalfViewModelFactory
to define a Kotlin class called CalfViewModelFactory. Anything in between the()
brackets is part of theprimary constructor
. Inside the primary constructor we haveprivate val calfDAO: CalfDAO
, which thanks to theprivate
keyword creates a class member variable that is only visible inside this class(can not be accessed from outside the class). In Kotlin we put the type after the variable name, socalfDAO:CalfDAO
means we have created a class variable called calfDAO of type CalfDAO.- Lastly we have
: ViewModelProvider.Factory
, the:
is how we explicitly state that our class is implementing theViewModelProvider.Factory
interface
- Lastly we have
Override function
- Now we can talk about this chunk of code:
override fun <T : ViewModel> create(modelClass: Class<T>): T
- The
override
keyword is how implement and override(replace) thecreate()
function we get from theViewModelProvider.Factory
interface. - To get a basic understanding of the code above we need to learn about about how functions are declared in Kotlin. A function declaration begins with the
fun
keyword, followed by the function name, a parameter list and the return type. So with that simple knowledge we know thatoverride fun <T : ViewModel?> create(modelClass: Class<T>): T
is a function calledcreate
takes in one parameter called modelClass and returns a class of typeT
. To understand anything in between the<>
brackets we need to talk about generics and generic functions.
Generics
- With generics we can define what are called
type parameters
. Type parameters make it possible to choose the types at the moment of an objects creation and makes our code a lot more flexible.
Generic functions
- In general we create a generic function when we want the function to be able to operate on multiple class types. With a generic function we place the type parameters before the name of the function, such as:
fun <T : ViewModel> create
- The syntax of
T : ViewModel
is called anupper bound
. The type specified after the:
is called theupper bound
, indicating that only a subtype of ViewModel can be substituted for T.
Function parameters
- The syntax of
create(modelClass: Class<T>): T
might seem fairly straight forward. The name of the function iscreate
, the function takes in one parameter calledmodelClass
of typeClass<T>
and returns an object of typeT
. Wait, what isClass<T>
? If you think that looks like the Java class Class you would be right, that is some Java in our Kotlin code. Does that mean Java code can be run in our Kotlin code? Actually yes, it can and the documentation even states :
Kotlin is designed with Java interoperability in mind. Existing Java code can be called from Kotlin in a natural way, and Kotlin code can be used from Java rather smoothly as well. In this section, we describe some details about calling Java code from Kotlin.
- So
modelClass: Class<T>
basically means that it takes in the class Java class Class of the type parameter T that we defined earlier.
The body of the function:
modelClass.isAssignableFrom(CalfViewModel::class.java)
- We have already discussed that
modelClass
is a Java class Class.isAssignableFrom()
is a method that is used to determine if the class or interface represented by the Class object is either the same as or is a super class of themodelClass
class.CalfViewModel::class.java
is how we access the underlying.class
file(bytecode) for the CalfViewModel class. So all of this together is how we check to make sure that modelClass is of type CalfViewModel. It's mainly confusing because we are using the Java reflection API instead of the Kotlin one. Why are we using the Java reflection API and not the Kotlin one? I am not 100% sure but I do know that there are times that the Java API is preferable over the Kotlin one
Return type
- Lastly we return a new instance of the
CalfViewModel
,
return CalfViewModel(calfDAO) as T
- the
as T
is just a simple casting done to make our function returns a ViewModel
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.
💖 💪 🙅 🚩
Tristan Elliott
Posted on June 8, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.