DEV Community

loading...
Cover image for Working with LiveData on Android in Kotlin

Working with LiveData on Android in Kotlin

Aayush Gupta
A 22 y.o. Android Developer from Bhilai who also happens to be an avid FOSS Contributor
・3 min read

LiveData library allows developers to update the UI seamlessly as data updates regardless of the data type. This is a great addition to DRY Principle as well. Moreover, It works perfectly well with the ViewModel library which makes this a great choice for the developers.

In case you are unaware of the ViewModel library, feel free to check out my old article on it.

Usage

Dependency

To use LiveData, we need to add a dependency on the androidx-lifecycle library.

dependencies {
    // LiveData
    def lifecycle_version = "2.2.0"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
}
Enter fullscreen mode Exit fullscreen mode

Implementations

LiveData has 2 implementations:

It looks like MutableLiveData differs from LiveData only by making the setValue() and postValue() methods public, whereas in LiveData they are protected.

What are some reasons to make a separate class for this change and not simply define those methods as public in the LiveData itself?

Generally speaking, is such…

Using MutableLiveData

We will be creating a simple counter app to show the usage of the library. You should be able to use it in a similar pattern with the ViewModel library and any of your other projects.

Here is how my activity_main.xml looks like:

<?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="40sp"
        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="Button"
        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 we will create a variable to store the counter value and increment it on button press. This variable will be of type MutableLiveData<Int> and will create an instance of the MutableLiveData class with a constructor of the initial value.

var counter: MutableLiveData<Int> = MutableLiveData(0)
Enter fullscreen mode Exit fullscreen mode

Value of LiveData object can be obtained by using value property.

Now we can call the observe method over it to do some specific action every time the value updates. This requires arguments for the class owner and Observer function in which we can define our actions.

I will be using ViewBinding to interact with GUI components. In case you are unaware of the topic, you can check out my article over it.

counter.observe(this, Observer {
     binding.textView.text = counter.value.toString()
})
Enter fullscreen mode Exit fullscreen mode

and we need to implement the logic in the button to actually increment the counter.

binding.button.setOnClickListener {
    counter.value?.let {
        counter.value = it + 1
    }
}
Enter fullscreen mode Exit fullscreen mode

Here is how MainActivity.kt looks in my case:

package dev.theimpulson.livedataexample

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import dev.theimpulson.livedataexample.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 counter: MutableLiveData<Int> = MutableLiveData(0)

        counter.observe(this, Observer {
            binding.textView.text = counter.value.toString()
        })

        binding.button.setOnClickListener {
            counter.value?.let {
                counter.value = it + 1
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

With this our app is now complete. You can build and run it to observe that UI will increment as soon as you click the button.

Using LiveData

As I stated earlier that LiveData is immutable. Therefore, one cannot set its value. This is particularly useful if you want to make an object observable but with a private setter.

In the current case, here is how it could have been done:

private val _counter: MutableLiveData<Int> = MutableLiveData(0)

fun counter(): LiveData<Int> {
    return _counter
}

counter().observe(this, Observer {
    binding.textView.text = counter().value.toString()
})

binding.button.setOnClickListener {
    _counter.value?.let {
         _counter.value = it + 1
    }
}
Enter fullscreen mode Exit fullscreen mode

As you can notice that I made _counter which is of type MutableLiveData which is private and it will be limited to the class. In case one wants to observe its value, they must use the counter() function which is of type LiveData whose setter is private. This will ensure that one cannot modify the value of the counter outside of the class. I hope that clears how you can use LiveData as well.

While these were very short example, I hope this still makes it clear how powerful and useful this library is for the developers. I recommend using LiveData in conjunction with ViewModel to get the most out of both libraries.

Discussion (0)