Understanding the ViewModelProvider.Factory interface in Android with Kotlin

theplebdev

Tristan Elliott

Posted on June 8, 2022

Understanding the ViewModelProvider.Factory interface in Android with Kotlin

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")
    }
}

Enter fullscreen mode Exit fullscreen mode
  • 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

Enter fullscreen mode Exit fullscreen mode
  • is the most normal looking.We use class CalfViewModelFactory to define a Kotlin class called CalfViewModelFactory. Anything in between the () brackets is part of the primary constructor. Inside the primary constructor we have private val calfDAO: CalfDAO, which thanks to the private 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, so calfDAO: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 the ViewModelProvider.Factory interface

Override function

  • Now we can talk about this chunk of code:
override fun <T : ViewModel> create(modelClass: Class<T>): T
Enter fullscreen mode Exit fullscreen mode
  • The override keyword is how implement and override(replace) the create() function we get from the ViewModelProvider.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 that override fun <T : ViewModel?> create(modelClass: Class<T>): T is a function called create takes in one parameter called modelClass and returns a class of type T. 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
Enter fullscreen mode Exit fullscreen mode
  • The syntax of T : ViewModel is called an upper bound. The type specified after the : is called the upper 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 is create, the function takes in one parameter called modelClass of type Class<T> and returns an object of type T. Wait, what is Class<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)
Enter fullscreen mode Exit fullscreen mode
  • 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 the modelClass 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
Enter fullscreen mode Exit fullscreen mode
  • 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.
💖 💪 🙅 🚩
theplebdev
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.

Related