LiveData

In a previous post I mentioned LiveData and I said I will talk about it in the future, I think now is a good time to talk about LiveData because in my Last (post) I talked about ViewModel, and I gave an example of how to use ViewModel to provide and maintain your data for your UI components (aka Activity or Fragment). Both ViewModel and LiveData are parts of the Android architecture components. According to the documentation “Android architecture components are a collection of libraries that help you design robust, testable, and maintainable apps. Start with classes for managing your UI component lifecycle and handling data persistence.”
So What is LiveData?
Again according to the documentation “LiveData is a data holder class that can be observed within a given lifecycle”. This means you set up an observer in such as Activity of Fragment and that observer will be notified if its wrapped data changed, instead of requesting the data each time from the ViewModel; but that notification happens only in Activity or Fragment active state(Started or Resumed). LiveData is considered a wrapper that can be used with any data including objects that implements collections such as List. A LiveData object usually lives in the ViewModel class.
In this post, I will give you an example of how we can use LiveDate. We will build a simple application containing one text view and one button when the button is pressed a text will appear in the text view. This example is based on the famous game “Werewolf”. This example as the last post contains a ViewModel and also the Live Data is defined in the View Model itself. So let’s start coding.
I used the following dependencies:

implementation "android.arch.lifecycle:extensions:1.1.1"
kapt "android.arch.lifecycle:compiler:1.1.1"

And now sync the project.

activity_main.xml is as follows:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    android:background="@drawable/werewolf"
    tools:context="com.narbase.livedataexample.MainActivity">

    <TextView
        android:id="@+id/roleTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:text="Hello"
        android:gravity="center"
        android:textSize="26sp"
        android:layout_marginBottom="12dp"
        android:layout_marginLeft="24dp"
        android:layout_marginRight="24dp"
        android:background="@drawable/rectangle"/>

    <Button
        android:id="@+id/showRoleButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        tools:text="Show role"
        android:layout_gravity="center"
        android:text="@string/show_role"/>

</LinearLayout>

There are some drawables and strings that I used in the actvity_main.xml, you will find it in the complete project in Github.

I called the ViewModel RoleViewModel, the RoleViewModel class is as follows:

package com.narbase.livedataexample

import android.arch.lifecycle.MutableLiveData
import android.arch.lifecycle.ViewModel
import java.util.*

class RoleViewModel: ViewModel() {

    private val wereWolfRole: List<String> = listOf(
            "Mason",
            "Seer",
            "Villager",
            "Tanner",
            "Hunter",
            "Werewolf"
    )
    var currentRole = MutableLiveData<String>()

    fun getRole(): String {
        val random = Random()
        val randIndex = random.nextInt(wereWolfRole.size)
        return wereWolfRole[randIndex]
    }

}

I used the Random class, so each time you use getRole() function it will return a random string from the list.

The MutableLiveData class has setValue() (synchronously) and postValue() (asynchronously) methods, these methods are public and can be used to change the value stored in a LiveData object.

The MainActivty is as follow:

package com.narbase.livedataexample

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.arch.lifecycle.ViewModelProviders
import android.arch.lifecycle.Observer
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    private val viewModel by lazy { obtainViewModel() }

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

        setupObservers()
        setupShowRoleButton()
    }

    private fun obtainViewModel() =  ViewModelProviders.of(this).get(RoleViewModel::class.java)

    private fun setupObservers() {
        viewModel.currentRole.observe(this,  Observer { role -> changeRoleText(role) })
    }

    private fun changeRoleText(role: String?) {
        roleTextView.text = role
    }

    private fun setupShowRoleButton() {
        showRoleButton.setOnClickListener {
            val role = viewModel.getRole()
            viewModel.currentRole.postValue(role)
        }
    }
}

When we press the Show Role button, the data is changed and post its new value to LiveDate using postValue().

In most cases, setup observes in onCreate() method is better, so there will be no redundant calls from onResume() method and to ensure that as soon as the activity or fragment becomes active they will have data to be displayed.

The output of the app will be as follows:

This is a simple example of how to use LiveData and you can know more about it in Android Developers website. And you can find the project in Github. So that’s for this week. If you have any thoughts or questions please share them with us in comments.

Till next week.

Leave a Reply

Your email address will not be published. Required fields are marked *