What is LiveData?

One of the sweetest introductions to to android development as part of android jetpack was the LiveData. LiveData is a class used to hold data that then become live. By being live the changes made to the held data is immediately available to the observer. The Observer is the object that needs to be notified when the changes occur. You can have multiple observers.

However what makes LiveData especially different from other observables is the fact that it is lifecycle-aware. Thus it respects the lifecycle of the app components. Remember android has several components like activities, fragments and services, each with it’s own unique lifecycle callbacks.
LiveData respects these by providing updates to only components that in active state. To LiveData, an active component or rather a component in active state is one that has either been started or resumed already.

The problem LiveData solves

Before Android Architecture components were introduced by Google, developers had already come up with several design patterns like Model View Presenter and Model View Controller. These helped solve the problem of spaghetti code where you bundle logic, data and User interface code within activities and fragments thus leading to unmaintenability. Using those patterns allowed developers to be able to write more maintenable code.

However those are just development patterns and have no knowledge of android components lifecycle. This is an important problem because android’s fundamental building are it’s components and these components have unique lifecycle. The components’ state depend on the lifecycle. Generally that state can either be active or inactive. So we have to explicitly cater for this situation when passing data to our various components. This adds complexity since we have to cater for the unique lifecycle of the each component we intend to work with.

Thus android engineers introduced android jetpack, a colection of libraries, tools, and guidance to help developers write high-quality apps easier. Part of the introduced libraries include the ViewModel as well as the LiveData classes. These generally work hand in hand to allow us pass data to the UI. ViewModel is lifecycle aware and uses LiveData to pass data to the UI. The data is listened to by observers.

LiveData can be listened to by various observers. These observers can be in different states, some active and some inactive. However this is no problem as LiveData is lifecycle aware and will only update the observers in active state. This is an advantage of LiveData over other observable mechanisms like the RxJava.

With LiveData you won’t need to be checking states of components or even unsubscribing your subscribers when the component is being paused,stopped or destroyed.When the component is being resumed, LiveData will automatically notify the observer in that component of any updates.

Implementations of LiveData

As an abstract class LiveData can’t be instantiated and used directly. Instead we can use some of the concrete implementations that have been provided for us.

These include:

(a). MutableLiveData

The most commonly used. All you need to do is instantiate it using the new keyword.

    private MutableLiveData<Integer> mutableLiveData=new MutableLiveData<>();

The above indicates using the generic parameter that we will hold an integer.

In kotlin:

val mutableLiveData = MutableLiveData<String>()

The above indicates that we will hold a String.

NB/= It’s recommended you do this in the ViewModel class.

Then you need an Observer that defines the onChanged() method. It is through this method that we will be notified of updates.

        Observer<Integer> liveDataObserver=new Observer<Integer>() {
            @Override
            public void onChanged(@Nullable Integer integer) {
                timerTV.setText("Elapsed : "+integer+ " s");
            }
        };

The above code is our observer. In order to actually register it we:

        myViewModel.getLiveData().observe(this,liveDataObserver);

Full MutableLiveData Example

(a). Creating an infinte timer

We want to create a simple timer that will count for us time from a specified beginning upto an infinite time, or until the app is closed or paused. We will use classes, Timer and TimerTask for scheduling our timer.

The seconds will be passed to the user interface from our ViewModel class using the MutableLiveData.

Video Tutorial

Here is a video tutorial:

Step 1: Add Lifecycle Extensions and Compiler in your gradle scripts.

Go to your app level build gradle and add them as follows:

    // Lifecycle components
    implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
    annotationProcessor 'androidx.lifecycle:lifecycle-compiler:2.0.0'

Here is the whole dependencies closure:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    testImplementation 'junit:junit:4.12'
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

    implementation 'com.google.android.material:material:1.0.0'
    implementation 'androidx.cardview:cardview:1.0.0'

    // Lifecycle components
    implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
    annotationProcessor 'androidx.lifecycle:lifecycle-compiler:2.0.0'
}
Step 2: Prepare Layout

Here is the activity_main.xml layout:

<?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">

    <androidx.cardview.widget.CardView
        android:layout_width="160dp"
        android:layout_height="190dp"
        android:layout_margin="10dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:foreground="?android:attr/selectableItemBackground">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:orientation="vertical">

            <ImageView
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:background="@drawable/m_circle_bg_pink"
                android:padding="10dp"
                android:src="@drawable/m_info" />

            <TextView
                android:id="@+id/tvCounter"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:text="Seconds: "
                android:textStyle="bold" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:padding="5dp"
                android:text="Android LiveData Example"
                android:textColor="@android:color/darker_gray" />

        </LinearLayout>

    </androidx.cardview.widget.CardView>

</androidx.constraintlayout.widget.ConstraintLayout>
Step 3: Create ViewModel Class

Create a class called MyViewModel.java and add imports as follows:

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

import java.util.Timer;
import java.util.TimerTask;

public class MyViewModel extends ViewModel {

Instantiate our MutableLiveData and initialize other fields:

    //MutableLiveData is a LiveData which publicly exposes setValue(T) and
    // postValue(T) method.
    private MutableLiveData<Integer> mutableLiveData=new MutableLiveData<>();

    private static int BEGIN_AFTER = 1000, INTERVAL = 1000;
    private static int counter = 0;

Then define a method to start our timer at a specified moment then increment it after a given interval:

    private void startTimer(){
        Timer timer=new Timer();
        //Schedule the specified task for repeated fixed-rate execution,
        // beginning after the specified delay. Subsequent executions
        // take place at approximately regular intervals, separated by
        // the specified period.
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                mutableLiveData.postValue(counter++);
            }
        },BEGIN_AFTER,INTERVAL);
    }

Let’s start the timer in our constructor:

    //Constructor
    public MyViewModel(){
       startTimer();
    }

Then publicly expose our MutableLiveData to any observer:

    public MutableLiveData<Integer> getLiveData() {
        return mutableLiveData;
    }

FULL CODE : MyVideModel.java

package info.camposha.counterlivedata;

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

import java.util.Timer;
import java.util.TimerTask;

public class MyViewModel extends ViewModel {

    //MutableLiveData is a LiveData which publicly exposes setValue(T) and
    // postValue(T) method.
    private MutableLiveData<Integer> mutableLiveData=new MutableLiveData<>();

    private static int BEGIN_AFTER = 1000, INTERVAL = 1000;
    private static int counter = 0;

    private void startTimer(){
        Timer timer=new Timer();
        //Schedule the specified task for repeated fixed-rate execution,
        // beginning after the specified delay. Subsequent executions
        // take place at approximately regular intervals, separated by
        // the specified period.
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                mutableLiveData.postValue(counter++);
            }
        },BEGIN_AFTER,INTERVAL);
    }
    //Constructor
    public MyViewModel(){
       startTimer();
    }
    public MutableLiveData<Integer> getLiveData() {
        return mutableLiveData;
    }
}
//end

Step 4: Create our MainActivity

Here we will create our Observer then subscribe it to our MutableLiveData:

    private void renderUpdates(){
        final TextView timerTV=findViewById(R.id.tvCounter);
        MyViewModel myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);

        Observer<Integer> liveDataObserver=new Observer<Integer>() {
            @Override
            public void onChanged(@Nullable Integer integer) {
                timerTV.setText("Elapsed : "+integer+ " s");
            }
        };
        myViewModel.getLiveData().observe(this,liveDataObserver);
    }

FULL CODE: MainActivity.java

package info.camposha.counterlivedata;

import android.os.Bundle;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;

public class MainActivity extends AppCompatActivity {

    private void renderUpdates(){
        final TextView timerTV=findViewById(R.id.tvCounter);
        MyViewModel myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);

        Observer<Integer> liveDataObserver=new Observer<Integer>() {
            @Override
            public void onChanged(@Nullable Integer integer) {
                timerTV.setText("Elapsed : "+integer+ " s");
            }
        };
        myViewModel.getLiveData().observe(this,liveDataObserver);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        this.renderUpdates();
    }
}

Download

Full Code for: CounterLiveData

References: Android Developers Documentation.

Good day.