Android Viewmodel And Livedata Complete Guide

 Last Update:2025-06-22T00:00:00     .NET School AI Teacher - SELECT ANY TEXT TO EXPLANATION.    7 mins read      Difficulty-Level: beginner

Understanding the Core Concepts of Android ViewModel and LiveData

Android ViewModel and LiveData: Detailed Explanation with Important Information

Lifecycle Awareness Both ViewModel and LiveData are integral components of the Jetpack Architecture Components framework. They are designed to be aware of the lifecycle of the UI (Activity or Fragment) they are attached to. This means that they handle configuration changes without losing the associated data and prevent memory leaks by automatically detaching themselves from the UI when it is destroyed.

ViewModel

Purpose A ViewModel acts as a central repository of UI-related data that is not dependent on the activity or fragment's lifecycle. This allows the UI to stay consistent while being destroyed and recreated during configuration changes, such as screen rotations or language settings switches.

Key Features

  1. Data Survives Configuration Changes: When an activity or fragment is destroyed and recreated due to configuration changes, the ViewModel survives. As a result, the data it holds, such as user inputs or network responses, remains intact.
  2. Handles UI-Related State: The ViewModel provides data to the UI components and manages their state in a lifecycle-conscious way.
  3. Avoids Memory Leaks: Because the ViewModel is not tied to the activity or fragment, it ensures that long-running operations do not cause memory leaks.
  4. Simplified Communication: It simplifies communication between different UI components (e.g., fragments within the same activity).

Example of Usage

public class MyViewModel extends ViewModel {
    private MutableLiveData<String> currentName;

    public MutableLiveData<String> getCurrentName() {
        if (currentName == null) {
            currentName = new MutableLiveData<String>();
        }
        return currentName;
    }

    public void setName(String name) {
        currentName.postValue(name);
    }
}

Retrieving ViewModel Instance Use the ViewModelProvider or ViewModelProvider.Factory to get an instance of the ViewModel. This ensures that the ViewModel is retained across configuration changes.

MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);

Benefits

  • Consistency: Data consistency across config changes without needing to use onSaveInstanceState() method.
  • Efficiency: Reduces boilerplate code for retaining data and simplifies data management.
  • Testing: Easier to test as UI-related business logic can be moved to the ViewModel.

LiveData

Purpose LiveData is an observable data holder class following the observer pattern. It is lifecycle-aware, meaning it respects the lifecycle of other app components such as activities, fragments, or services. This awareness ensures that LiveData only updates app component observers that are in an active lifecycle state.

Key Features

  1. Automatic Lifecycle Management: Only updates observers that are in an active lifecycle state (STARTED or RESUMED).
  2. Thread Safety: Ensures that the latest data is delivered to the observer regardless of the thread from which the value is set.
  3. Sticky Nature: Observers receive the most recent value even if they start observing after the event is posted.
  4. Data Binding: Seamlessly integrates with Data Binding and Android UI, which helps in reducing boilerplate code related to updating the UI.

Example of Usage

public class MyViewModel extends ViewModel {
    private MutableLiveData<String> currentName = new MutableLiveData<>();

    public LiveData<String> getName() {
        return currentName;
    }

    public void setName(String name) {
        currentName.setValue(name);
    }
}

Updating LiveData LiveData values can be updated using setValue() or postValue(). The primary difference is that setValue() should be called from the main thread, whereas postValue() can be used from background threads.

Benefits

  • UI Consistency: Automatically updates the UI when the data changes but only when the UI is active.
  • Threading Efficiency: Manages threading internally to deliver updates on the main thread.
  • Memory Efficient: Only stores necessary copies of data and avoids unnecessary updates to inactive components.

Combining ViewModel and LiveData

When combined, ViewModel and LiveData offer a streamlined approach to handling UI-related data. The ViewModel stores the data, and the LiveData acts as an observer for this data, ensuring that the UI updates reactively based on data changes.

Architecture Overview

  1. UI Component: Activity or Fragment responsible for displaying data.
  2. ViewModel: Acts as a mediator between UI and data source. Handles data and provides it to the UI via LiveData.
  3. LiveData: Observes data changes and notifies UI components only when they are in an active lifecycle state.
  4. Repository/Data Source: Layer responsible for fetching data either from a local database or a remote server.

Lifecycle-Aware Observing The key advantage of LiveData over traditional observer patterns is its lifecycle-aware nature. By attaching observers only for the active lifecycle states (STARTED and RESUMED), LiveData ensures that app components receive updates only when they are visible or interactable, thus avoiding unnecessary processing during inactive states.

Example Flow

  1. Activity/Fragment: Subscribes to the LiveData object held in the ViewModel.
  2. ViewModel: Queries data from a Repository and posts it to the LiveData.
  3. Repository/Data Source: Fetches data from a database or network and returns it to the ViewModel.

Best Practices

  • Encapsulation: Always encapsulate LiveData objects, providing getter methods instead of exposing them directly.
  • Data Transformation: Use Transformations or MediatorLiveData to transform or merge multiple LiveData sources.
  • Background Operations: Avoid complex data processing tasks within the ViewModel itself. Instead, delegate these tasks to repositories or workers.

Online Code run

🔔 Note: Select your programming language to check or run code at

💻 Run Code Compiler

Step-by-Step Guide: How to Implement Android ViewModel and LiveData

Step 1: Set Up Your Project

  1. Create a New Project:

    • Open Android Studio.
    • Click on "Start a new Android Studio project".
    • Choose "Empty Activity".
    • Name your application (e.g., CounterApp).
    • Choose a language (Kotlin for this example).
    • Click "Finish" to create the project.
  2. Add Required Dependencies:

    • Open build.gradle (Module: app) and add the following dependencies for ViewModel and LiveData:
      dependencies {
          def lifecycle_version = "2.6.1"
          implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
          implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
      }
      
    • Click "Sync Now" to sync your project with the Gradle files.

Step 2: Create a ViewModel

  1. Create a New Kotlin Class:

    • In the app/src/main/java/com/example/counterapp directory, create a new Kotlin class named CounterViewModel.
  2. Implement the ViewModel:

    • Inside CounterViewModel.kt, define a MutableLiveData to store the counter value and a function to increment the counter:
      package com.example.counterapp
      
      import androidx.lifecycle.LiveData
      import androidx.lifecycle.MutableLiveData
      import androidx.lifecycle.ViewModel
      
      class CounterViewModel : ViewModel() {
      
          private val _counter = MutableLiveData<Int>().apply {
              value = 0
          }
          val counter: LiveData<Int> get() = _counter
      
          fun incrementCounter() {
              _counter.value = (_counter.value ?: 0) + 1
          }
      }
      

Step 3: Set Up the Activity

  1. Open MainActivity.kt:

    • Inside the MainActivity.kt file, we will set up the ViewModel and observe the LiveData.
  2. Modify MainActivity.kt:

    • Here is the complete code for MainActivity.kt:
      package com.example.counterapp
      
      import android.os.Bundle
      import androidx.activity.viewModels
      import androidx.appcompat.app.AppCompatActivity
      import androidx.lifecycle.Observer
      import com.example.counterapp.databinding.ActivityMainBinding
      
      class MainActivity : AppCompatActivity() {
      
          private lateinit var binding: ActivityMainBinding
          private val viewModel: CounterViewModel by viewModels()
      
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              binding = ActivityMainBinding.inflate(layoutInflater)
              setContentView(binding.root)
      
              // Observe the counter LiveData
              viewModel.counter.observe(this, Observer { newCount ->
                  binding.counterText.text = newCount.toString()
              })
      
              // Set up the button click listener
              binding.incrementButton.setOnClickListener {
                  viewModel.incrementCounter()
              }
          }
      }
      

Step 4: Add Layout Resources

  1. Open res/layout/activity_main.xml:

    • Modify the layout to include a TextView to display the counter and a Button to increment it.
  2. Modify activity_main.xml:

    • Here is the complete code for activity_main.xml:
      <?xml version="1.0" encoding="utf-8"?>
      <layout 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">
      
          <data>
              <variable
                  name="counterViewModel"
                  type="com.example.counterapp.CounterViewModel" />
          </data>
      
          <androidx.constraintlayout.widget.ConstraintLayout
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              tools:context=".MainActivity">
      
              <TextView
                  android:id="@+id/counterText"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:text="0"
                  android:textSize="48sp"
                  app:layout_constraintBottom_toTopOf="@+id/incrementButton"
                  app:layout_constraintEnd_toEndOf="parent"
                  app:layout_constraintStart_toStartOf="parent"
                  app:layout_constraintTop_toTopOf="parent" />
      
              <Button
                  android:id="@+id/incrementButton"
                  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_constraintStart_toStartOf="parent"
                  app:layout_constraintTop_toBottomOf="@+id/counterText" />
          </androidx.constraintlayout.widget.ConstraintLayout>
      </layout>
      

Step 5: Bind ViewModel to Layout (Optional)

  1. Modify activity_main.xml (Optional):

    • If you want to bind the ViewModel directly in the layout using Data Binding, you can do so. However, we have already handled the binding in the MainActivity.kt. Here is how you can do it:
  2. Modify activity_main.xml for Data Binding:

    • Here is the updated activity_main.xml for Data Binding:
      <?xml version="1.0" encoding="utf-8"?>
      <layout 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">
      
          <data>
              <variable
                  name="counterViewModel"
                  type="com.example.counterapp.CounterViewModel" />
          </data>
      
          <androidx.constraintlayout.widget.ConstraintLayout
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              tools:context=".MainActivity">
      
              <TextView
                  android:id="@+id/counterText"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:text="@{String.valueOf(counterViewModel.counter)}"
                  android:textSize="48sp"
                  app:layout_constraintBottom_toTopOf="@+id/incrementButton"
                  app:layout_constraintEnd_toEndOf="parent"
                  app:layout_constraintStart_toStartOf="parent"
                  app:layout_constraintTop_toTopOf="parent" />
      
              <Button
                  android:id="@+id/incrementButton"
                  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_constraintStart_toStartOf="parent"
                  app:layout_constraintTop_toBottomOf="@+id/counterText" />
          </androidx.constraintlayout.widget.ConstraintLayout>
      </layout>
      
  3. Modify MainActivity.kt for Data Binding (Optional):

    • Here is the updated MainActivity.kt for Data Binding:

You May Like This Related .NET Topic

Login to post a comment.