Android LiveData With Example

Today I wanna tell you about a few solutions that have been developed. Solutions for problems that I think all of us as a developer have been trying to solve again and again in every project.

So, let’s say that I want to perform actions in response to changes in lifecycle status of Android Component. Sometimes you may wanna observe certain values being changed over the configuration change. We all faced these problems somewhere down the road, trying a lot of different patterns MVP, MVVM, and others. But to implement these patterns is also a big problem for beginners.

So, the good news is with the Android Architecture Component and more precisely with the lifecycle LiveData and ViewModel, we can easily overcome these problems.

In my previous article, I briefly explain what is ViewModel and how we can use it in our app with the example. So go ahead and check it out.

LiveData:

LiveData is an observable data holder. It is also a lifecycle aware. By lifecycle aware I mean, it can only be observed in the context of a lifecycle, more precisely in the context of an Activity or Fragment lifecycle. By passing the reference of an Activity or Fragment, it can understand whether your UI onScreen, offScreen or Destroyed. After passing the UI object to LiveData, whenever the data in the live data changes. It notifies the lifecycle owner with updates and then the UI redraw itself with updates.

Advantages of LiveData:

  1. No memory leaks: Observers are bound to Lifecycle objects and clean up after themselves when their associated life cycle destroyed.
  2. No crashes due to stopped activities: It means if an activity is in the back stack, then it doesn’t receive any LiveData stream.
  3. Always up to date: It receives the latest data upon becoming active again.
  4. No more manual life-cycling handle: Observers just observe relevant data and don’t stop or resume observation. LiveData manages all of this under the hood.
  5. Ensures your UI matches the data state: LiveData notifies the observer object whenever lifecycle state changes. Instead of updating the UI every-time when the data changes, your observer can update the UI every time there’s a change.
  6. Proper configuration changes: If an observer is recreated due to a configuration change, like device rotation, it immediately receives the latest available data.
  7. Sharing resources: You can extend LiveData object using the singleton pattern to wrap system services so that they can be shared in your app.

Android App Setup:

So, enough of this theory lets see how we can use this in our Android app. For to use LiveData add the following dependency in the build.gradle file.

implementation "android.arch.lifecycle:extensions:$current_version"
annotationProcessor "android.arch.lifecycle:compiler:1.0.0"

Creating a LiveData:

For creating an instance of LiveData to hold a certain type of data. It usually creates inside the ViewModel class. Now I’m going to use my previous article example where we make the Color Changer app. For color changer app we first need a ViewModel to hold our current background color.

You see the demo right. Let’s create a LiveData inside ViewModel.


class ColorChangerViewModel : ViewModel() {

    val colorResource = MutableLiveData<Int>()

    init {
        colorResource.value = 0xfff
    }
}

If you remembered from the previous article the colorResource is the Int value. In here it is MutableLiveData.

Note: Make sure to store LiveData objects that update the UI in ViewModel objects, as opposed to an activity or fragment. You see our UI controllers are only responsible to store data not for holding data state. By UI controllers mean our ViewModel and LiveData class.

What is MutableLiveData:

MutableLiveData is also a LiveData. Internally MutableLiveData extends LiveData class and exposes the two methods publically which is setValue and getValue. With setValueyou can set the new value and after that, it calls all the active observers with new modified value. And last, with getValue, you can get the recent value stored inside the LiveData instance.

Ways of Setting Data:

There are currently two ways of setting the value inside the LiveData instance. The first one we’ve seen which is setValue and second one is postValue. The setValue method is used to set data from Main Thread. If the code executed inside the Worker Thread or Background Thread you can use the postValue method.

So, we create our ViewModel and LiveData let’s see how we gonna use this ViewModel inside our activity.

MainActivity:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val colorChangerViewModel = ViewModelProviders.of(this).get(ColorChangerViewModel::class.java)
        colorChangerViewModel.colorResource.observe(this, object: Observer<Int> {
            override fun onChanged(t: Int?) {
                mainActivityRootView.setBackgroundColor(t!!)
            }
        })
        changeColorButton.setOnClickListener {
            colorChangerViewModel.colorResource.value = generateRandomColor()
        }
    }

    private fun generateRandomColor(): Int {
        val rnd = Random()
        return Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256))
    }
}

 

In most cases, the onCreate method is the right place to begin observing a LiveData object. To start observing the data you call the observe method on LiveData instance. For the observe method first argument you pass the UI in this the activity and the second argument Observer which is just a callback.

When setValue is called the onChanged is immediately invoked providing the most recent value stored inside the colorResource. In onChanged you will call the code to update the UI in our case updating the background color.

Like I said earlier you can change LiveData value with setValue or postValue method. In our case, we’re using setValue because we’re updating the data from Main Thread. When we update the data value by calling setValue or postValue, it notifies all the active Observers immediately.

Another Example:

Let’s move a step up and create a real-life problem example. In this example, we’re going to make a timer app. When the app opens it shows the current time and after every 2 seconds time will be updated.

So you see the demo right. Now let’s create our ViewModel class for Timer app.

TimeChangerViewModel:
class TimeChangerViewModel : ViewModel() {
    val timerValue = MutableLiveData<Long>()
    
    init {
        timerValue.value = System.currentTimeMillis()
        startTimer()
    }

    private fun startTimer() {
        disposable = Observable.interval(2, 2, TimeUnit.SECONDS)
                .subscribe({
                    timerValue.postValue(System.currentTimeMillis())
                }, Throwable::printStackTrace)
    }
}

You see when TimeChangerViewModel initializes we start the timer with the interval of 2 seconds. For creating a time interval I use RxJava2 library. One thing noticeable here that I’m using the postValue method because the interval method subscribes the value in the Background Thread. 

MainActivity:
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val timeChangerViewModel = ViewModelProviders.of(this).get(TimeChangerViewModel::class.java)
        val calendar = Calendar.getInstance()
        timeChangerViewModel.timerValue.observe(this, Observer<Long> { t ->
            Log.e("TimeValue", t.toString())
            calendar?.timeInMillis = t!!
            timTextView.text = calendar.time.toString()
        })
    }
}

The activity is very basic after setting the Observer to LiveData when the timerValue inside the TimeChangerViewModel change it immediately called the onChanged with the new time value. The LiveData stop posting the values if our app is in the back stack. I tested the app by adding the Logcat.

Note: When we receive the time value inside the Observer, it gives us data in the Main Thread. Even though our data posting the value in the Background Thread. It automatically converts it for us under the hood.

Stop Listening LiveData:

At some point, you may need to stop observing the data. You can simply remove the observer with the given lifecycle.

someViewModel.liveData.removeObservers(lifecycle : this)

 

That’s it! I hope you like the post. If you’ve any queries regarding this please do comment below.

Download Complete Code

You can also check my next post on LiveData. In that post, I explain how to use map, swicthMap, and MediatorLiveData class for our own custom Transformation

Thank you for being here and keep reading…

LiveData Transformation

1 COMMENT

LEAVE A REPLY

Please enter your comment!
Please enter your name here