Lifecycle-Aware Components in Android

Nov 1 2022 · Kotlin 1.6, Android 12, Android Studio Chipmunk 2021.2.1

Part 1: Lifecycle-Aware Components in Android

10. Explore LiveData as a Lifecycle-Aware Component

Episode complete

Play next episode

Next
About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 09. Subscribe to Custom Lifecycle Owner Next episode: 11. Use LiveData With a Fragment

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Transcript: 10. Explore LiveData as a Lifecycle-Aware Component

Well, so far in this course we have seen how to create your own lifecycle-aware components.

Now, the question arises, in Android is there any pre-defined lifecycle aware component? Well, the answer is Yes. There are many. And among them, the most important one is the LiveData.

So let’s understand what this LiveData is all about and where does this fit in our application.

In front of you is a typical lifecycle of an Activity. The Activity is created, becomes active. We rotate the screen, the Activity is destroyed and recreated in new screen configuration.

We call finish(), the Activity is finally destroyed. And through out this activity’s lifecycle, we use ViewModel which keeps are data intact. Because ViewModel has fantastic capability to keep the data safe even during - such configuration.

And in this ViewModel, we use LiveData to hold data for our Activity which survives through the configuration change.

Well, the concept behind the LiveData is very simple. It’s an observable data holder class, which means it can store data and it can notify the observers when that data changes.

So in our case, if this T changes, then it will notify the Activity that hey the data has changed, you can now update the UI elements as applicable. And remember this T is a generic type. It could be any class your choice.

Another, important feature worth to quote here is that, LiveData notifies the Activity about the data change - only when the Activity is in Active state. Which means when the Activity is in between STARTED or RESUMED state - only then LiveData notifies the Activity about the data change.

Otherwise, if the Activity is going through destructive states such as onPause through onDestroy then LiveData does not send any updates to the Activity. Fine? This is another proof which makes LiveData a lifecycle-aware component. So let’s see some code in action.

Well, right now in our applicable, if you try loading the random recipe, there is no sign of progress bar in our Activity. Fine? i.e. if you take a look at activity_main.xml, you’ll find we have a progress bar in our layout whose visibility is by default GONE.

So let’s use this progress bar to show the progress while we are loading data on the screen. And for that we will use LiveData this time. So let’s go to our MainViewModel. Here, let’s create a backing property loadingState.

  val loadingState: LiveData<UiLoadingState>

  private val _loadingState = MutableLiveData<UiLoadingState>()
  val loadingState: LiveData<UiLoadingState>
    get() {
      return _loadingState
    }

with its backing field

  private val _loadingState = MutableLiveData<UiLoadingState>()

and return the backing field.

    get() {
      return _loadingState
    }

Perfect!

And notice that we are using LiveData of type UiLoadingState. Well, this UiLoadingState is nothing but a sealed class which represents two states - when we are loading something and when we not loading something. So in this function getRamdomRecipe() when our repository layer is busy loading some data.

We can update the state of LiveData _loadingState to Loading.

    _loadingState.value = UiLoadingState.Loading

So, we can access the actual value stored in LiveData using the value property. Fine? This is something you need to remember. And of course, once we are done with loading data, within this callback we can update the _loadingState to NotLoading. Great!

  fun getRandomRecipe() {

    _loadingState.value = UiLoadingState.Loading

    viewModelScope.launch {
      recipeRepository.getRandomRecipe().collect { result ->
        _loadingState.value = UiLoadingState.NotLoading
        _recipeState.value = result
      }
    }
  }

Okay, so we have created our LiveData and we are updating its value as well. So now, there has to be an observer that should observe these data updates. And that observer will be our MainActivity of course.

So within our MainActivity which is connected to our MainViewModel. Within onCreate function, we can use MainViewModel instance access loadingState LiveData and call observe() method. As a first parameter we have to pass the instance of the LifecycleOwner which is MainActivity in our case. So we will pass this and the second parameter is the trailing lambda where we can use Observer interface callback.

Within this, we are going to receive UiLoadingState updates - using which we can update our UI by calling handleLoadingState() function. Perfect!

  viewModel.loadingState.observe(this, Observer { uiLoadingState ->
      handleLoadingState(uiLoadingState)
  })

Well, this handleLoadingState() function is basically responsible to update Views. Such as show or hide the progress bar as per the loading state. Let’s run the application. Okay, we saw a progress bar initially when the data loaded. Let’s load data again. So here we go I can see the progress bar working absolutely fine. So this way we can use LiveData and notify the observer about any data changes.