Introduction

In the last blog post I explored a simple use case with the new ViewModel class for saving basketball score data during a configuration change. ViewModels are designed to hold and manage UI-related data in a life-cycle conscious way. ViewModels allow data to survive configuration changes such as screen rotations.

At this point, you might have a few questions about the breadth of what ViewModels do. In this post I’ll be answering:

Do ViewModels persist my data? TL;DR No. Persist as normal!

TL;DR No. Persist as normal! Are ViewModels a replacement for onSaveInstanceState ? TL;DR No, but they are related so keep reading.

TL;DR No, but they are related so keep reading. UPDATED 5/15/2019: How do I use ViewModels to save and restore UI state efficiently? T̶L̶;̶D̶R̶ ̶Y̶o̶u̶ ̶u̶s̶e̶ ̶a̶ ̶c̶o̶m̶b̶i̶n̶a̶t̶i̶o̶n̶ ̶o̶f̶ ̶V̶i̶e̶w̶M̶o̶d̶e̶l̶s̶,̶ ̶o̶n̶S̶a̶v̶e̶I̶n̶s̶t̶a̶n̶c̶e̶S̶t̶a̶t̶e̶(̶)̶ ̶a̶n̶d̶ ̶l̶o̶c̶a̶l̶ ̶p̶e̶r̶s̶i̶s̶t̶e̶n̶c̶e̶.̶ TL;DR You use ViewModels and the ViewModel Saved State module alongside local persistence.

T̶L̶;̶D̶R̶ ̶Y̶o̶u̶ ̶u̶s̶e̶ ̶a̶ ̶c̶o̶m̶b̶i̶n̶a̶t̶i̶o̶n̶ ̶o̶f̶ ̶V̶i̶e̶w̶M̶o̶d̶e̶l̶s̶,̶ ̶o̶n̶S̶a̶v̶e̶I̶n̶s̶t̶a̶n̶c̶e̶S̶t̶a̶t̶e̶(̶)̶ ̶a̶n̶d̶ ̶l̶o̶c̶a̶l̶ ̶p̶e̶r̶s̶i̶s̶t̶e̶n̶c̶e̶.̶ TL;DR You use ViewModels and the ViewModel Saved State module alongside local persistence. Are ViewModels a replacement for Loaders? TL;DR. Yes, ViewModels used in conjunction with a few other classes can replace Loaders.

UPDATED 5/15/2019 for the new ViewModel Saved State module. Note that the section “How do I use ViewModels to save and restore UI state efficiently?” has an update at the top for the ViewModel Saved State module currently in alpha.

Do ViewModels persist my data?

TL;DR No. Persist as normal!

ViewModels hold transient data used in the UI but they don’t persist data. Once the associated UI Controller (fragment/activity) is destroyed or the process is stopped, the ViewModel and all the contained data gets marked for garbage collection.

Data used over multiple runs of the application should be persisted like normal in a local database, Shared Preferences, and/or in the cloud. If you want the user to be able to put the app into the background and then come back three hours later to the exact same state, you should also persist data. This is because as soon as your activity goes into the background, your app process can be stopped if the device is running low on memory. There’s a handy table in the activity class documentation which describes in which activity lifecycle states your app is stoppable:

As a reminder, when an app processes is stopped due to resource constraints, it’s stopped without ceremony and no additional lifecycle callbacks are called. This means that you can’t rely on onDestroy being called. You do not have a chance to persist data at the time of process shutdown. Therefore, if you want to be the most sure that you won’t lose data, persist it as soon as the user enters it. This means that even if your app process is shut down due to resource constraints or if the device runs out of battery, the data will be saved. If you’re willing to concede losing data in instances of sudden device shutdown, you can save the data in the onStop() callback, which happens right as the activity is going into the background.

Are ViewModels a replacement for onSaveInstanceState?

TL;DR No, but they are related so keep reading.

To understand the subtleties of this difference, it’s helpful to understand the difference between onSaveInstanceState() and Fragment.setRetainInstance(true)

onSaveInstanceState(): This callback is meant to retain a small amount of UI related data in two situations:

The app’s process is stopped when it’s in the background due to memory constraints.

Configuration changes.

onSaveInstanceState() is called in situations in which the activity is stopped, but not finished, by the system. It is not called when the user explicitly closes the activity or in other cases when finish() is called.

Note that a lot of UI data is automatically saved and restored for you:

“The default implementation of this method saves transient information about the state of the activity’s view hierarchy, such as the text in an EditText widget or the scroll position of a ListView widget.” — Saving and Restoring Instance State Documentation

These are also good examples of the type of data that is meant to be stored in onSaveInstanceState() . onSaveInstanceState() is not designed to store large amounts of data, such as bitmaps. onSaveInstanceState() is designed to store data that is small, related to the UI and not complicated to serialize or deserialize. Serialization can consume lots of memory if the objects being serialized are complicated. Because this process happens on the main thread during a configuration change, it needs to be fast so that you don’t drop frames and cause visual stutter.

Fragment.setRetainInstance(true): The Handling Configuration Changes documentation describes a process for storing data during a configuration change using a retained fragment. This sounds less useful than onSaveInstanceState() which covers both configuration changes as well as process shutdown. The usefulness of creating a retained fragment is that it’s meant to retain large sets of data such as images or to retain complex objects like network connections.

ViewModels only survive configuration change-related destruction; they do not survive the process being stopped. This makes ViewModels a replacement for using a fragment with setRetainInstance(true) (in fact ViewModels use a fragment with setRetainInstance set to true behind the scenes).

Additional ViewModel benefits

ViewModels and onSaveInstanceState() address UI data in very different ways. onSaveInstanceState() is a lifecycle callback, whereas ViewModels fundamentally change the way UI data is managed in your app. Here are a few more thoughts on the benefits of using ViewModel in addition to onSaveInstanceState() :

ViewModels encourage good architectural design. Your data is separated from your UI code , which makes the code more modular and simplifies testing.

, which makes the code more modular and simplifies testing. onSaveInstanceState() is designed to save a small amount of transient data, but not complex lists of objects or media data. A ViewModel can delegate the loading of complex data and also act as temporary storage once this data is loaded .

is designed to save a small amount of transient data, but not complex lists of objects or media data. . onSaveInstanceState() is called during configuration changes and when the activity goes into the background; in both of these cases you actually do not need to reload or process the data if you keep it in a ViewModel.

How do I use ViewModels to save and restore UI state efficiently?