An easy example on how to use Jetpack ViewModel and LiveData
Last updated on

An easy example on how to use Jetpack ViewModel and LiveData

Android
AndroidKotlin#Import 2025-05-27 00:21

Jetpack broken up into four main areas: Architecture, Foundation, Behavior and UI.

ViewModel

ViewModel helped to achieve two things:

  • help the project to adopt MVVM architecture
  • hold the data in the memory in a life-cycle manner

One of the benefits of using ViewModel is the data can be kept while screen is rotated.

LiveData

LiveData can apply observer pattern to a variable, thus you can bind the data changes to the UI component.

One example of using both ViewModel and LiveData

We are going to create a simple example which only has three parts on the UI:

Screenshot_20200722_111122_au.com.flyingbits.jetpacktestkotlin

Simply as it is, +1 button will add the total value by 1, -1 button will minus the total by -1.

Step 1: install ViewModel and LiveData plugins.

On the Google Android's document website, you can install ViewModel along with lifecycle or you can just install the target plugin.

def lifecycle_version = "2.2.0"

// ViewModel implementation “androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version” implementation ‘androidx.lifecycle:lifecycle-extensions:$lifecycle_version’

// ViewModel implementation “androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version” // LiveData implementation “androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version” // Lifecycles only (without ViewModel or LiveData) implementation “androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version”

// Saved state module for ViewModel implementation “androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version”

// Annotation processor kapt “androidx.lifecycle:lifecycle-compiler:$lifecycle_version” // alternately - if using Java8, use the following instead of lifecycle-compiler implementation “androidx.lifecycle:lifecycle-common-java8:$lifecycle_version”

// optional - helpers for implementing LifecycleOwner in a Service implementation “androidx.lifecycle:lifecycle-service:$lifecycle_version”

// optional - ProcessLifecycleOwner provides a lifecycle for the whole application process implementation “androidx.lifecycle:lifecycle-process:$lifecycle_version”

// optional - ReactiveStreams support for LiveData implementation “androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version”

// optional - Test helpers for LiveData testImplementation “androidx.arch.core:core-testing:$arch_version”

I would recommend to install the following two plugins if you are only use ViewModel and LiveData:

// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"

Step 2: MyViewModel.kt

Create the ViewModel inherited from ViewModel class with only one observable variable inside: num, which is used to hold the total shown in the screenshot.

package com.flyingbits.kotlinlearn

import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel

class MyViewModel: ViewModel() {

private var num: MutableLiveData<Int> = MutableLiveData(0)

public fun getNum(): MutableLiveData<Int> {
    return this.num
}

public fun addNum(n: Int) {
    this.num.value = this.num.value!! + n
}

}

Step 3: MainActivity.kt

Here is the complete code for MainActivity:

package com.flyingbits.kotlinlearn

import android.os.Bundle import android.util.Log import android.view.View import android.widget.Button import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentTransaction import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProviders

class MainActivity : AppCompatActivity() {

private var myViewModel: MyViewModel? = null
private val TAG: String = "Running Order"
private var btn1: Button? = null
private var btn2: Button? = null
private var textView: TextView? = null

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

    Log.d(TAG, "onCreate in called")

    myViewModel = ViewModelProvider(this)[MyViewModel::class.java]
    btn1 = findViewById(R.id.button1)
    btn2 = findViewById(R.id.button2)
    textView = findViewById(R.id.textView)
    
    myViewModel!!.getNum().observe(this, Observer<Int>() {
        textView?.setText(myViewModel!!.getNum().value.toString())
    })

    btn1?.setOnClickListener {
        myViewModel!!.addNum(1)
    }

    btn2?.setOnClickListener {
        myViewModel!!.addNum(-1)
    }

}

}

Step 4: Layout of the MainActivity

<?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">
&lt;TextView
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:text=&quot;Hello World!&quot;
    android:id=&quot;@+id/text_view&quot;
    app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
    app:layout_constraintLeft_toLeftOf=&quot;parent&quot;
    app:layout_constraintRight_toRightOf=&quot;parent&quot;
    app:layout_constraintTop_toTopOf=&quot;parent&quot; /&gt;

&lt;Button
    android:id=&quot;@+id/button_add&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:text=&quot;+1&quot;
    app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
    app:layout_constraintEnd_toEndOf=&quot;parent&quot;
    app:layout_constraintHorizontal_bias=&quot;0.216&quot;
    app:layout_constraintStart_toStartOf=&quot;parent&quot;
    app:layout_constraintTop_toTopOf=&quot;parent&quot;
    app:layout_constraintVertical_bias=&quot;0.762&quot; /&gt;

&lt;Button
    android:id=&quot;@+id/button_minus&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:text=&quot;-1&quot;
    app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
    app:layout_constraintEnd_toEndOf=&quot;parent&quot;
    app:layout_constraintHorizontal_bias=&quot;0.832&quot;
    app:layout_constraintStart_toStartOf=&quot;parent&quot;
    app:layout_constraintTop_toTopOf=&quot;parent&quot;
    app:layout_constraintVertical_bias=&quot;0.762&quot; /&gt;

</androidx.constraintlayout.widget.ConstraintLayout>

By far you have successfully implemented the viewModel and liveData in your project.

  • If you are running the app now, you can see +1 button will increase the total value, -1 button will reduce value.
  • If the screen is rotated, the total value will kept on the screen.

The complete project you can download from: https://github.com/arkilis/jetpack-mvvm

Reference

  • GHOST_URL/an-easy-example-on-how-to-use-viewmodel-and-livedata