// Tutorial //

Android LiveData

Published on August 3, 2022
Default avatar
By Anupam Chugh
Developer and author at DigitalOcean.
Android LiveData

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

In this tutorial, we’ll be discussing the LiveData architectural component in our Android Application. For a better understanding of this tutorial, do take a quick detour to Android ViewModel.

Android LiveData

LiveData is a part of the architecture patterns. It’s basically a data holder that contains primitive/collection types. It’s used for observing changes in the view and updating the view when it is ACTIVE. Thus, LiveData is lifecycle aware. We know that ViewModels are used to communicate the data to the View. Using ViewModels alone can be a tedious and costly operation since we need to make multiple calls each time the data has to alter the View. Plus we need to store the data Model at different places. LiveData is based on the Observer Pattern and makes the communication between the ViewModel and View easy. It observes for data changes and updates the data automatically instead of us doing multiple calls in adding and deleting data references from multiple places (for example SQLite, ArrayList, ViewModel).

Android LiveData vs RxJava

Android LiveData is somewhat similar to RxJava except that LiveData is lifecycle aware. It won’t update your data in the view if the View is in the background. This helps us in avoiding exceptions like IllegalStateException etc. How does our LiveData in the ViewModel update the Activity? When we register the Observer in our Activity, we need to override the method onChanged(). The method onChanged() would get trigger whenever the LiveData is changed. Thus in the onChanged(), we can update the changed LiveData onto the View.

LiveData is just a data type which notifies it’s observer whenever the data is changed. LiveData is like a data changed notifier.

LiveData notifies the observer using setValue() and postValue(). setValue() runs on the main thread. postValue() runs on the background thread. Invoking getValue() on the LiveData type instance would return you the current data.


MutableLiveData is just a class that extends the LiveData type class. MutableLiveData is commonly used since it provides the postValue(), setValue() methods publicly, something that LiveData class doesn’t provide. LiveData/MutableLiveData is commonly used in updating data in a RecyclerView from a collection type(List, ArrayList etc). In the following section, we’ll create an application that adds/deletes rows in a RecyclerView from the SQLite Database. We’ll use MutableLiveData that updates the RecyclerView records whenever the LiveData changes. We’ll use DiffUtil to update the minimum number of RecyclerView row by comparing the old and new ArrayList.

Android LiveData Example Project Structure

android livedata example project structure Add the following in your build.gradle file:

implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'android.arch.lifecycle:extensions:1.1.1'

Android LiveData Code

The code for the activity_main.xml layout is given below:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android"


            app:popupTheme="@style/AppTheme.PopupOverlay" />


    <RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"

            android:layout_height="match_parent" />


        app:srcCompat="@android:drawable/ic_input_add" />


The code for the list_item_row.xml layout is given below:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="https://schemas.android.com/apk/res/android"


            android:textSize="20sp" />

            android:layout_below="@+id/tvUrl" />

            android:src="@android:drawable/ic_menu_delete" />



The code for DbSettings.java class is given below:

package com.journaldev.androidlivedata.db;

import android.provider.BaseColumns;

public class DbSettings {

    public static final String DB_NAME = "favourites.db";
    public static final int DB_VERSION = 1;

    public class DBEntry implements BaseColumns {

        public static final String TABLE = "fav";
        public static final String COL_FAV_URL = "url";
        public static final String COL_FAV_DATE = "date";


The code for FavouritesDbHelper.java class is given below:

package com.journaldev.androidlivedata.db;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class FavouritesDBHelper extends SQLiteOpenHelper {

    public FavouritesDBHelper(Context context) {
        super(context, DbSettings.DB_NAME, null, DbSettings.DB_VERSION);

    public void onCreate(SQLiteDatabase db) {
        String createTable = "CREATE TABLE " + DbSettings.DBEntry.TABLE + " ( " +
                DbSettings.DBEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
                DbSettings.DBEntry.COL_FAV_URL + " TEXT NOT NULL, " +
                DbSettings.DBEntry.COL_FAV_DATE + " INTEGER NOT NULL);";

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + DbSettings.DBEntry.TABLE);


The code for Favourites.java model class is given below:

package com.journaldev.androidlivedata;

public class Favourites {

    public long mId;
    public String mUrl;
    public long mDate;

    public Favourites(long id, String name, long date) {
        mId = id;
        mUrl = name;
        mDate = date;

    public Favourites(Favourites favourites) {
        mId = favourites.mId;
        mUrl = favourites.mUrl;
        mDate = favourites.mDate;


So in our SQLite database we create a Table with three records : ID, URL, DATE. The code for FavouritesViewModel.java class is given below:

package com.journaldev.androidlivedata;

import android.app.Application;
import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.MutableLiveData;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.journaldev.androidlivedata.db.DbSettings;
import com.journaldev.androidlivedata.db.FavouritesDBHelper;
import java.util.ArrayList;
import java.util.List;

public class FavouritesViewModel extends AndroidViewModel {

    private FavouritesDBHelper mFavHelper;
    private MutableLiveData<List<Favourites>> mFavs;

    FavouritesViewModel(Application application) {
        mFavHelper = new FavouritesDBHelper(application);

    public MutableLiveData<List<Favourites>> getFavs() {
        if (mFavs == null) {
            mFavs = new MutableLiveData<>();

        return mFavs;

    private void loadFavs() {
        List<Favourites> newFavs = new ArrayList<>();
        SQLiteDatabase db = mFavHelper.getReadableDatabase();
        Cursor cursor = db.query(DbSettings.DBEntry.TABLE,
                new String[]{
                null, null, null, null, null);
        while (cursor.moveToNext()) {
            int idxId = cursor.getColumnIndex(DbSettings.DBEntry._ID);
            int idxUrl = cursor.getColumnIndex(DbSettings.DBEntry.COL_FAV_URL);
            int idxDate = cursor.getColumnIndex(DbSettings.DBEntry.COL_FAV_DATE);
            newFavs.add(new Favourites(cursor.getLong(idxId), cursor.getString(idxUrl), cursor.getLong(idxDate)));


    public void addFav(String url, long date) {

        SQLiteDatabase db = mFavHelper.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put(DbSettings.DBEntry.COL_FAV_URL, url);
        values.put(DbSettings.DBEntry.COL_FAV_DATE, date);
        long id = db.insertWithOnConflict(DbSettings.DBEntry.TABLE,

        List<Favourites> favourites = mFavs.getValue();

        ArrayList<Favourites> clonedFavs;
        if (favourites == null) {
            clonedFavs = new ArrayList<>();
        } else {
            clonedFavs = new ArrayList<>(favourites.size());
            for (int i = 0; i < favourites.size(); i++) {
                clonedFavs.add(new Favourites(favourites.get(i)));

        Favourites fav = new Favourites(id, url, date);

    public void removeFav(long id) {
        SQLiteDatabase db = mFavHelper.getWritableDatabase();
                DbSettings.DBEntry._ID + " = ?",
                new String[]{Long.toString(id)}

        List<Favourites> favs = mFavs.getValue();
        ArrayList<Favourites> clonedFavs = new ArrayList<>(favs.size());
        for (int i = 0; i < favs.size(); i++) {
            clonedFavs.add(new Favourites(favs.get(i)));

        int index = -1;
        for (int i = 0; i < clonedFavs.size(); i++) {
            Favourites favourites = clonedFavs.get(i);
            if (favourites.mId == id) {
                index = i;
        if (index != -1) {


MutableLiveData holds a List of Favourite instance objects. In the addFav() and removeFav() we notify data changes to the Observer that’s defined in MainActivity. We create a copy of the ArrayList in order to compare the old and new one. The code for MainActivity.java class is given below:

package com.journaldev.androidlivedata;

import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.util.DiffUtil;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;

import java.util.Date;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private FavAdapter mFavAdapter;
    private FavouritesViewModel mFavViewModel;
    private List<Favourites> mFav;
    FloatingActionButton fab;

    protected void onCreate(Bundle savedInstanceState) {
        fab = findViewById(R.id.fab);
        final RecyclerView recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        mFavViewModel = ViewModelProviders.of(this).get(FavouritesViewModel.class);
        final Observer<List<Favourites>> favsObserver = new Observer<List<Favourites>>() {
            public void onChanged(@Nullable final List<Favourites> updatedList) {
                if (mFav == null) {
                    mFav = updatedList;
                    mFavAdapter = new FavAdapter();
                } else {
                    DiffUtil.DiffResult result = DiffUtil.calculateDiff(new DiffUtil.Callback() {

                        public int getOldListSize() {
                            return mFav.size();

                        public int getNewListSize() {
                            return updatedList.size();

                        public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
                            return mFav.get(oldItemPosition).mId ==

                        public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
                            Favourites oldFav = mFav.get(oldItemPosition);
                            Favourites newFav = updatedList.get(newItemPosition);
                            return oldFav.equals(newFav);
                    mFav = updatedList;

        fab.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                final EditText inUrl = new EditText(MainActivity.this);
                AlertDialog dialog = new AlertDialog.Builder(MainActivity.this)
                        .setTitle("New favourite")
                        .setMessage("Add a url link below")
                        .setPositiveButton("Add", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                String url = String.valueOf(inUrl.getText());
                                long date = (new Date()).getTime();

                                mFavViewModel.addFav(url, date);
                        .setNegativeButton("Cancel", null)

        mFavViewModel.getFavs().observe(this, favsObserver);

    public class FavAdapter extends RecyclerView.Adapter<FavAdapter.FavViewHolder> {

        public FavViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_row, parent, false);
            return new FavViewHolder(itemView);

        public void onBindViewHolder(FavViewHolder holder, int position) {
            Favourites favourites = mFav.get(position);
            holder.mTxtDate.setText((new Date(favourites.mDate).toString()));

        public int getItemCount() {
            return mFav.size();

        class FavViewHolder extends RecyclerView.ViewHolder {

            TextView mTxtUrl;
            TextView mTxtDate;

            FavViewHolder(View itemView) {
                mTxtUrl = itemView.findViewById(R.id.tvUrl);
                mTxtDate = itemView.findViewById(R.id.tvDate);
                ImageButton btnDelete = itemView.findViewById(R.id.btnDelete);
                btnDelete.setOnClickListener(new View.OnClickListener() {
                    public void onClick(View view) {
                        int pos = getAdapterPosition();
                        Favourites favourites = mFav.get(pos);


In the above code, we’ve defined the ReyclerView Adapter class in the Activity itself. mFavViewModel.getFavs().observe(this, favsObserver); is used to set an Observer in the MainActivity that’ll be notified from the ViewModel class whenever the LiveData is updated. The favsObserver anonymous class consists of the onChanged() method which provides the latest data which is then updated int the RecyclerView. The output of the above application in action is given below. android livedata example app This brings an end to Android LiveData tutorial. You can download the project from the link below.

Download AndroidLiveData Project.

You can also checkout Android Studio project code from our GitHub Repository

If you’ve enjoyed this tutorial and our broader community, consider checking out our DigitalOcean products which can also help you achieve your development goals.

Learn more here

About the authors
Default avatar
Developer and author at DigitalOcean.

Still looking for an answer?

Was this helpful?

Anupam, thank you for this tutorial. Is it necessary to make a clone of the list in order to change the value of the MutableLiveData? In other words, would calling mFav.setValue() with the original list as the parameter still cause a change to be observed?

- Josh Rogers

    Anupam: I have a background task ( in a separate activity) started by using the enqueue method in the main activity . My background task writes data to an external SD Card continuously to test the endurance of the card. Periodically, I want to display the number of bytes written to the card. I am using MutableLiveData to pass the value from my background task to my main activity for display on the screen. i cannot get the data to the onObserver() in my main activity. If I set up an onClick() in the main activity to respond to a button click I can get the onObserver() to run and display data that I set in the onClick(). But, when I cannot get the data from the background task to get to the onObserver() in the main activity. Does MuteableLiveData work for sending data between activities? Thank you for your time and thiss very informative article.

    - john faro

      Have you looked at Kotlin language?

      - Igor Ganapolsky

        In your demo project, i was getting this exception: Caused by: java.lang.RuntimeException: Cannot create an instance of class com.journaldev.androidlivedata.FavouritesViewModel. It is solved by making constructor as public in FavouritesViewModel class. Please check this answer https://stackoverflow.com/a/44998087/4698320

        - Danish