Android ViewModelProvider Factory Passing Parameter to ViewModel In Kotlin

In the previous tutorial we learned about one of the Android Architecture Components, ViewModel with LiveData , we have seen example using ViewModel how objects survives configuration changes (On Screen-Rotate) there we did'nt create ViewModel on our own by default ViewModelProviders instantiate ViewModels with no arg constructor.

So if I have a ViewModel with multiple arguments, then I need to use a Factory that I can pass to ViewModelProviders to use when an instance of ViewModel is required let's see sample example for demo .

1. Gradle


Add ViewModel Architecture Component dependency to gradle .


file: build.gradle(app)
dependencies {
 
 implementation "android.arch.lifecycle:extensions:1.1.1"
 annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
}


2. API Helper Class


Create a class APIHelper , this is class reference we pass as argument to ViewModel .

file : ApiHelper.kt
package com.tutorialsbuzz.viewmodelfactorysample.data

class ApiHelper {
    fun getUserInfo(): String = (0..10).random().toString() + " Hello World"
}


3. ViewModel


  • Create a MainViewModel by extending ViewModel class .
  • Constructor of MainViewModel takes APIHelper reference . 
  • Define a LiveData by wrapping to the String data variable .

file : MainViewModel.kt
package com.tutorialsbuzz.viewmodelfactorysample

class MainViewModel(private val apiHelper: ApiHelper) : ViewModel() {

    val userInfo = MutableLiveData<String>().apply { postValue("") }

    fun getUsersInfo() {
        userInfo.postValue(apiHelper.getUserInfo())
    }

}


4. ViewModelProvider Factory


  • Create ViewModelFactory by extending ViewModelProvider.Factory interface .
  • Override the create function which creates a new instance of the given class .
  • @param  modelClass a class whose instance is requested
  • @param <T> the type parameter for the ViewModel.
  • @return a newly created ViewModel

file : ViewModelFactory.kt
package com.tutorialsbuzz.viewmodelfactorysample

class ViewModelFactory(private val apiHelper: ApiHelper) : ViewModelProvider.Factory {

    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
            return MainViewModel(apiHelper) as T
        }
        throw IllegalArgumentException("Unknown class name")
    }
}


5. XML


Create XML Layout activity_main.xml , this will be set as content view for launcher Activity (MainActivity.kt) and add TextView and Button to your layout file .

file : activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tvNumber"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:gravity="center"
        android:text=""
        android:textSize="30sp" />

    <Button
        android:id="@+id/update"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="30dp"
        android:gravity="center"
        android:text="update"
        android:textSize="30sp" />

</LinearLayout>



6. MainActivity


  • Create a koltin class MainActivity.kt and extend it to AppCompatActivity class .
  • Override onCreate function and set the content of this MainActivity with above defined xml layout (activity_main.xml). 

Setting Up ViewModel :

  • ViewModelProviders is a utility class that provides ViewModels for a given Activity scope .
  • ViewModelProviders.Factory interface are responsible to instantiate ViewModels.
  • ViewModelProvider.of is a static function .
 Parameter :
  1. An activity, in whose scope ViewModels should be retained
  2. Factory to instantiate new ViewModels

 Returns : 
  a ViewModelProvider instance

The get function on ViewModelProvider returns  ViewModel instance of the given Type . 
viewModel = ViewModelProviders.of(this,ViewModelFactory(ApiHelper()))
		   .get(MainViewModel::class.java)

Setting Up Observer : 

 
LiveData is defined in ViewModel , if any change change to live data can be observed .

viewModel.userInfo.observe(this, {
		tvNumber.text = it
	})
Main Activity Complete code .

file : MainActivity.kt
package com.tutorialsbuzz.viewmodelfactorysample

class MainActivity : AppCompatActivity() {

    private lateinit var viewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        setupViewModel()
        setUpObserver()

        update.setOnClickListener({
            viewModel.getUsersInfo()
        })

    }

    private fun setupViewModel() {
        viewModel = ViewModelProviders.of(
            this,
            ViewModelFactory(ApiHelper())
        ).get(MainViewModel::class.java)
    }

    private fun setUpObserver() {
        viewModel.userInfo.observe(this, {
            tvNumber.text = it
        })
    }

}





No comments:

Post a Comment