LiveData Tutorial for Android: Deep Dive
In this Android tutorial, you’ll learn about LiveData which is a core architecture component, and how to use it to its full potential in your app. By Prateek Sharma.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
LiveData Tutorial for Android: Deep Dive
30 mins
- Getting Started
- Lifecycle Aware Components
- LiveData and MutableLiveData
- Initialize, Update, Observe LiveData
- Synchronous vs Asynchronous Update
- LiveData in Action: Example One – Implement Search
- LiveData in Action: Example Two – Update Progress
- Transformations
- Transformations.map v/s Transformations.switchMap
- Transformations.switchMap – Example
- MediatorLiveData
- Example
- Custom LiveData
- Create Custom LiveData
- Consume Custom LiveData
- Optimize API Calls
- Handle Phone Rotation
- Event State Handling
- Multiple Event Emit Problem
- Solution
- RxJava vs LiveData
- Where to Go From Here?
Reactive Programming has been a buzz word nowadays. LiveData being one of the core Architecture Components, you can’t imagine not having it in a modern application. It is a simple yet powerful component, that can do wonders if you use it to its full potential.
LiveData helps to reduce memory leaks and manual lifecycle handling. It also ensures that UI is always up to date with the data even when the app’s activity is restarted while in use.
Through a real-world example of a MovieApp, you’ll learn:
- Types of LiveData
- Synchronous & Asynchronous Update
- Transformations & MediatorLiveData
- Extending LiveData
- State management by LiveData
You’ll work on an app named MovieApp. This app loads popular movies from TMDb API and allows to search for movies using a search term. You’ll also create a custom LiveData to handle internet connectivity status.
OK, it’s time to watch some movies now.
Getting Started
Download the project materials by clicking the Download Materials button at the top or bottom of this tutorial.
Launch Android Studio 4.0 or later and select Open an existing Android Studio project. Then navigate to and select the starter project folder.
This is how the project is structured:
Explore the project a bit, especially MainViewModel.kt in ui package and MovieListFragment.kt in movies package. In this tutorial, you will spend the most time in these files.
Open the app’s build.gradle and add the following dependency and sync the project:
implementation 'androidx.appcompat:appcompat:1.1.0'
This library alone contains ViewModel and LiveData. These are enough to start with LiveData.
As a first step, you’d need to get a key to use TMDb API. You can get one for free from TMDb official website. If you don’t already have an account, create one from the signup page. After you’ve created the account, log in and go to the API page. Choose the developer option, accept the terms and fill in your details to create a key. Copy the API Key from the API Details page. Once you have the key, open MovieApiModule.kt present in the framework.network package. Replace the placeholder value of TMDb_API_KEY
with your key.
Build and run the project. You’ll see only the search field and an empty RecyclerView.
Lifecycle Aware Components
AppCompatActivity and Fragment are some of the Lifecycle owner objects in the Android Framework. Lifecycle aware components are classes or objects that react based on lifecycle methods of Lifecycler owner. They react to changes in the lifecycle status of another component like Activity or Fragment. You can relate it with registering and unregistering location updates in an Activity’s onStart
and onStop
lifecycle methods.
LiveData and MutableLiveData
LiveData is a Lifecycle aware component and an observable data holder class. Before the introduction of LiveData, you might have used the callback mechanism to update your UI. However, callback has its own set of issues like manual handling of lifecycle, memory leaks, keeping up to date correct data to name a few.
The Android team designed LiveData to solve these issues. This is achieved by updating the UI only when the LiveData has an active observer. It also ensures that UI shows the latest data whenever it is visible to the user. In the next section, you’ll see how and where to initialize and update the LiveData and observe the LiveData.
Initialize, Update, Observe LiveData
LiveData is a wrapper on an object which can be observed from any UI component via a getter method. LiveData is generally initialized in ViewModel
and updated on some manual or automatic actions.
As an example, you can initialize, update, and observe LiveData as follows:
//1
val liveData: MutableLiveData<Any>()
//2
liveData.value = "Hello"
//3
liveData.observe(this, Observer {
// Update UI
})
Here’s what this code does:
- LiveData is always initialized with one of its child class’s constructors with exception of
Transformations
andMediatorLiveData
. More on that later. -
liveData
declared asval
can’t change, but you can always update the value of LiveData because it isMutableLiveData
. Any change in value ofliveData
notifies all of its active observers. - LiveData is always observed inside a UI Lifecycle owner, which can be an Activity or a Fragment. You receive the latest value of
liveData
inObserver
as an implicit parameterit
.
Synchronous vs Asynchronous Update
LiveData doesn’t have public methods to update its value. Hence you’ll use MutableLiveData
to update the value inside LiveData with the help of the following two options:
-
setValue
: sets the value instantly. This is synchronous update where main thread callssetValue
. With Kotlin’s property access syntax, you’ll often usevalue
instead ofsetValue
. -
postValue
: Asynchronous updating, means Observer doesn’t receive instant update, rather receives update when UI thread is active. When you callpostValue
more than one time from background thread, LiveData dispatches only the latest value to the downstream. Being asynchronous, this does not guarantee instant update to the Observer.
LiveData in Action: Example One – Implement Search
Now that you know how to initialize, update, and observe LiveData, it’s the right time to add the search feature. This will enable you to search for movies by matching title with the query text in the search field in MovieApp.
Open MovieListFragment.kt file, inside searchTextWatcher
. You’ll see afterTextChanged()
function calling the onSearchQuery()
with the search term as the only parameter. Here the search is initiated after the text changes inside the EditText
. In the steps below, you’ll implement what happens when the search is initiated.
First, open the MainViewModel.kt. Inside the class, declare the following at the top where other variables are declared.
val searchMoviesLiveData = MutableLiveData<List<Movie>>()
This declares LiveData as a class member. Movies fetched from the repository will go in searchMoviesLiveData
.
Next, inside the onSearchQuery()
function, replace the TODO
comment by the following:
fetchMovieByQuery(query)
When text length exceeds 2, the fetchMovieByQuery()
fetches movies based on the search query from API.
Lastly, inside the fetchMovieByQuery()
function, replace the TODO
comment by following:
searchMoviesLiveData.postValue(movies)
This updates searchMoviesLiveData
asynchronously after retrieving the list of movies, because fetching movies is a background task.
Till here you’ve done work required to fetch movies and update the LiveData. Now, it’s time to observe and watch some movies.
Open MovieListFragment.kt. At the end of the initialiseObservers()
method of the fragment, register this observer as below:
mainViewModel.searchMoviesLiveData.observe(viewLifecycleOwner, Observer {
movieAdapter.updateData(it)
})
This updates the adapter with fetched movies. The amazing thing about LiveData is, if UI is not in the foreground state, the observer will not receive any updates thus preventing the app from crashing.
You can search for your favorite movies now. Build and run the app.
Don’t go and watch your favorite movie right away, there’s a lot more to learn about LiveData :].