CodeNewbie Community 🌱

Cover image for Android Quicky: ViewModelProvider.Factory in Kotlin
Tristan
Tristan

Posted on

Android Quicky: ViewModelProvider.Factory in 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

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

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

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

Enter fullscreen mode Exit fullscreen mode
  • 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")
    }
Enter fullscreen mode Exit fullscreen mode
  • 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.

Oldest comments (0)