ViewModel library which is part of Jetpack Framework allows developers to preserve data in a life-cycle aware way. This means that data stored using this library persists in changes in the UI as long as its host activity/fragment is alive.
ViewModel is not a solution to preserve data in a persistent way but only temporarily. For persistent solutions, check out SharedPreferences, Room, or other libraries.
Usage
In order to use ViewModel, add a dependency on androidx.lifecycle's lifecycle-viewmodel-ktx
library in your module's build.gradle
file and sync the changes.
dependencies {
// ViewModel
def lifecycle_version = "2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
}
For every Activity or Fragment, whose data you want to preserve using ViewModel, creating a separate class is highly recommended.
I shall be creating a simple Counter app to demonstrate how to use this library while using ViewBinding in it to access the GUI components.
Here is the activity_main.xml
file:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textSize="50sp"
app:layout_constraintBottom_toTopOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Increment"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>
Now, to begin with, create a new class that will extend to the ViewModel class. Every object which relates to the data that you want to preserve using the ViewModel library should be inside this class.
In my case, I will create a MainActivityViewModel.kt
file to host the said class followed by a variable to store the counter's value and a simple function to increment the counter's value.
Here is how my MainActivityViewModel.kt
class will look like:
package dev.theimpulson.viewmodel
import androidx.lifecycle.ViewModel
class MainActivityViewModel: ViewModel() {
var counter = 0
fun increment() {
counter++
}
}
Now, inside my MainActivity, I will obtain an instance of the class I just created using ViewModelProvider class. You need to pass the current owner of the Activity as a constructor While using the get method on it with your class name as an argument.
Here is how it will look in my case:
val viewModel: MainActivityViewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)
Now, we can access our class's objects using this viewModel variable.
I will set the current counter value to match the value stored in the class. This will make sure that if UI rebuilds during usage of the app, the latest value is always reflected.
binding.textView.text = viewModel.counter.toString()
I will implement a setOnClickListener on the button to call the increment function as well as update the counter value in UI after it.
binding.button.setOnClickListener {
viewModel.increment()
binding.textView.text = viewModel.counter.toString()
}
Here is how my MainActivity.kt
file looks now:
package dev.theimpulson.viewmodel
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.lifecycle.ViewModelProvider
import dev.theimpulson.myapplication.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val viewModel: MainActivityViewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)
binding.textView.text = viewModel.counter.toString()
binding.button.setOnClickListener {
viewModel.increment()
binding.textView.text = viewModel.counter.toString()
}
}
}
and with that our app is now complete. You can now build it and check that the counter value persists even after UI rebuilds itself (rotate the screen to check it) and it gets reset once the app is closed/killed.
That's all there is to with ViewModel. It's a really simple and powerful library for the developers who need to preserve data till the Activity/Fragment is active.
Top comments (0)