Surviving Configuration Changes in Android
Learn how to survive configuration changes by handling your activities or fragment recreation the right way using either ViewModels, persistent storage, or doing it manually! By Beatrice Kinya.
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
Surviving Configuration Changes in Android
20 mins
- Getting Started
- Saving UI State in Instance State Bundles
- Using ViewModel to Store UI State
- Observing LiveData Changes
- Understanding Room Library
- Looking Into Data Entities
- Understanding Data Access Objects
- Exploring Database Class
- Saving a Search Term
- Reading Data From the App Database
- Managing Configuration Changes Yourself
- Where to Go From Here?
An Android device consistently changes configurations. This could be a screen orientation change, keyboard availability changes or a user switching to multi-window mode. During a configuration change, Android recreates existing activities to reload resources for the new configuration. To properly handle restarting an activity, it is important to restore the activity to its previous state.
In this tutorial, you’ll build BookHub App. This app allows users to search for books using the author’s name or the book title. Along the way, you’ll learn about:
- Saving and restoring activity state using instance state bundles.
- Using ViewModel to store UI state.
- Saving data in local persistent storage.
- Manually handling configuration changes.
Getting Started
Download the starter project by clicking the Download Materials button at the top or bottom of the tutorial.
Open Android Studio and import the starter project.
Build and run the project. You’ll see this screen:
The screen has an input field for entering an author’s name or a book title to search for books. It also has a search button with a magnifying glass icon and a label to show the number of books returned from a remote API, now showing no results.
Enter an author’s name and tap the search button. The app updates the result label with the number of books returned from the API:
Rotate the app, though, and you’ll see a different number:
Whoops! The books count got lost. When you rotated the screen, the app lost the count data because it recreated the activity to adapt to the new orientation. Your mission in this tutorial is to liven up the app while persisting data across configuration changes.
Check out the project structure:
The project has the following packages:
- data: This contains logic for accessing data sources such as the app database or remote APIs.
-
ui: The ui package has
SearchFragmentthat holds an input field for entering the author’s name or book title andSearchHistoryFragmentfor showing the search terms the user enters. It also hasBookViewModelthat holds UI-related data.Fragmentclasses are responsible for displaying data to the user. - repository: Its classes receive user actions like tapping a button. Then, they forward user requests to the data layer. The repository classes also receive data from the data layer — for instance, the list of books received from the remote API. Then, they forward the data received to the UI layer.
You’ll work across various classes in these packages as you build BookHub App.
Grab your coffee! It’s gonna be amazing.
Saving UI State in Instance State Bundles
When the system recreates the UI, you can save the UI state in an instance state bundle using onSaveInstanceState() lifecycle callback.
Instance state is a collection of key-value pairs stored in a Bundle object. It’s the data the app uses to restore UI controllers like an activity or a fragment to their previous state.
You’ll implement onSaveInstanceState() callback to save the value of bookscount when a user rotates the screen.
Open SearchFragment.kt and replace // TODO 1 with the following:
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt(bookCountKey, booksCount)
}
Here, you’re storing the value of booksCount in a Bundle object using bookCountKey key. The app calls onSaveInstanceState() immediately before calling onPause() to save the UI state.
To restore the saved state, you’ll fetch the stored value in the instance state bundle.
Replace // TODO 2 with this:
private fun restoreCount(savedInstanceState: Bundle?) {
// 1
booksCount = savedInstanceState?.getInt(bookCountKey) ?: 0
// 2
searchBinding.bookCountTextView.text = booksCount.toString()
}
Here’s what the code above does:
- Retrieves the value you stored in the instance state bundle using
bookCountKeykey and assigns it tobooksCount. - Restores the count pulled from saved state back to
bookCountTextView.
To call the method that retrieves the value stored in the state bundles, add this just above setTextChangedListener() in onCreateView():
restoreCount(savedInstanceState)
Build and run. Enter your favorite book title and tap the search button. You’ll see the following screen:
When you rotate the screen, the app retains the book count:
Congratulations! :]
onSaveInstanceState() serializes data to the disk. Serialization consumes a lot of memory when serializing large data sets or complex data structures such as bitmaps. This process happens in the main thread. Long-running serialization can cause UI jank during a configuration change. Therefore, you should store only primitives like Integer and small, simple objects like String in instance state bundles.
TransactionTooLargeException. This is another good reason to not process big data on a bundle.
BookHub App fetches a list of books from a remote API. How do you save the list of books to prevent the app from making another API call to fetch the books in case of a configuration change? In the following section, you’ll learn how to store data in a ViewModel to address this.
Using ViewModel to Store UI State
The Android team introduced ViewModel and LiveData classes to help save state during configuration changes.
A ViewModel stores and manages UI-related data in a lifecycle-conscious manner. Simply put, it allows data to survive configuration changes. A ViewModel remains in the memory until, the Lifecycle it is scoped to, goes away completely. For an activity, this means when it finishes; for a fragment when it’s when it’s detached.
The diagram below shows the lifetime of a ViewModel next to the lifecycle of the activity it’s associated with:
LiveData is an observable data-holder class. It’s lifecycle aware. It only notifies UI components that are in an active state when data changes.
Open BookViewModel.kt.
BookViewModel class extends ViewModel. It has three methods:
-
getBooks()to fetch books from a remote API. -
saveSearchTerm()that saves search terms entered by the user in the app database. -
getUserSearches()to retrieve search terms saved in the app database.
To add a LiveData object that saves the list of books fetched from the remote API, replace // TODO 3 with the following:
private val items = MutableLiveData<List<Item>?>()
val bookItems get() = items
Here, you’ve added a LiveData object that will store a list of books received from a remote API.
To store books returned from the API in items, your LiveData object, replace the getBooks() method with the following:
fun getBooks(searchTerm: String) {
viewModelScope.launch(Dispatchers.IO) {
// 1
val booksInfo = bookRepository.getBookInfo(searchTerm)
val books = booksInfo?.items
// 2
items.postValue(books)
}
}
Here’s what’s happening in the code above:
- Calls
getBookInfo()to fetch books from a remote API. The method returns a list of books. - Stores the list of books received from the API in
items.
To show the list of books in the UI, you’ll add an observer for bookItems.






