DEV Community

Cover image for Working with ViewModel in Android using Kotlin
Aayush Gupta
Aayush Gupta

Posted on • Updated on

Working with ViewModel in Android using Kotlin

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

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

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

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

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

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()
}
Enter fullscreen mode Exit fullscreen mode

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()
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

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)