Android Architecture Components--Saving UI States

In cases where the UI data to preserve is simple and lightweight, you might use onSaveInstanceState()alone to preserve your state data. In cases where you have complex data that you want to preserve, you can use a combination of ViewModel objects, the onSaveInstanceState() method, and persistent local storage.

Manging simpler cases: onSaveInstanceState()

The onSaveInstanceState() callback is designed to store relatively small amounts of data needed to easily reload the state of UI controller, such as an activity or a fragment, if the system stops and later recreates that controller. This callback is meant to handle two situations:

As both of these cases imply, onSaveInstanceState() is invoked in situations in which the activity is stopped, but not finished, by the system. For example, if the user leaves the app for several hours, and the system ejects the relevant process from memory, the system calls the default implementation of onSaveInstanceState() to save each UI controller that has an ID. Later, when the user returns to the app, the system restores the activity from the saved state.

Note: onSaveInstanceState() is not called when the user explicitly closes the activity or in other cases when finish()is called.

The system automatically saves and restores a lot of UI data for you: The default implementation of onSaveInstanceState() saves 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. You can also save custom data into this bundle by overriding the onSaveInstanceState() callback. If you override this method to save additional information not captured by each individual entity, you should call the default implementation unless you are prepared to save the states of every entity yourself.

onSaveInstanceState() is not designed to store large amounts of data, such as bitmaps, or complex data structures that require lengthy serialization or deserialization. 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, serialization can cause dropped frames and visual stutter if it takes too long. Therefore, instead of usingonSaveInstanceState() for complex data structures, make sure to store such structures in local persistent storage; it's a good idea to store the data as soon as it's created to minimize the chance of losing it. Then, use onSaveInstanceState() to store unique IDs for each of these objects.

Managing more complex states: divide and conquer

When you have more complex data structures that you need to preserve when an activity ends, you can efficiently save and restore UI state by dividing the work among several types of storage mechanisms.

There are two general ways a user can leave an activity, leading to two different outcomes the user may expect:

  • The user completely closes the activity. A user can completely close the activity if they swipe the activity off of the Recents screen, navigate up from the activity, or back out of the activity. The assumption in these cases is that the user has permanently navigated away from the activity, and if they ever re-open the activity, they will expect to start from a clean state.

  • The user rotates the phone or puts the activity in the background and then comes back to it. For example, the user performs a search and then presses the home button or answers a phone call. When they return to the search activity, they expect to find the search keyword and results still there, exactly as before.

To implement the behavior for complex data structures in either situation, you use local persistence, the ViewModel class, and theonSaveInstanceState() method together. Each of these approaches stores a different type of data used in the activity.

  • Local persistence: Stores all data you don’t want to lose if you open and close the activity.
    • Example: A collection of song objects, which could include audio files and metadata.
  • ViewModel: Stores in memory all the data needed to display the associated UI Controller.
    • Example: The song objects of the most recent search and the most recent search query.
  • onSaveInstanceState(): Stores a small amount of data needed to easily reload activity state if the system stops and then recreates the UI Controller. Instead of storing complex objects here, persist the complex objects in local storage and store a unique ID for these objects inonSaveInstanceState().
    • Example: Storing the most recent search query.

As an example, consider an activity that allows you to search through your library of songs. Here’s how different events should be handled:

When the user adds a song , the ViewModel immediately delegates persisting this data locally. If this newly added song is something that should be shown in the UI, you should also update the data in the ViewModel object to reflect the addition of the song. Remember to do all database inserts off of the main thread.

When the user searches for a song, whatever complex song data you load from the database for the UI Controller should be immediately stored in the ViewModel object. You should also save the search query itself in the ViewModel object.

When the activity goes into the background, the system calls onSaveInstanceState(). You should save the search query in theonSaveInstanceState() bundle. This small amount of data is easy to save. It’s also all the information you need to get the activity back into its current state.

Restoring complex states: reassembling the pieces

When it's time for the user to return to the activity, there are two possible scenarios for recreating the activity:

  • The activity is recreated after having been stopped by the system. The activity has the query saved in an onSaveInstanceState() bundle, and should pass the query to the ViewModel. The ViewModel sees that it has no search results cached, and delegates loading the search results, using the given search query.
  • The activity is created after a configuration change. The activity has the query saved in an onSaveInstanceState() bundle, and the ViewModelalready has the search results cached. You pass the query from the onSaveInstanceState() bundle to the ViewModel, which determines that it already has loaded the necessary data and that it does not need to re-query the database.

Note: When an activity is initially created, the onSaveInstanceState() bundle contains no data, and the ViewModel object is empty. When you create the ViewModel object, you pass an empty query, which tells the ViewModel object that there’s no data to load yet. Therefore, the activity starts in an empty state.

Depending on your activity implementation, you might not need to use onSaveInstanceState() at all. For example, a browser might take the user back to the exact webpage they were looking at before they exited the browser. If your activity behaves this way, you can forego usingonSaveInstanceState() and instead persist everything locally. In the song-searching example, that might mean persisting the most recent query in Shared Preferences.

Additionally, when you open an activity from an intent, the bundle of extras is delivered to the activity both when the configuration changes and when the system restores the activity. If the search query were passed in as an intent extra, you could use the extras bundle instead of theonSaveInstanceState() bundle.

In either of these scenarios, you’d still use a ViewModel to avoid wasting cycles reloading data from the database during a configuration change.

From: https://developer.android.com/topic/libraries/architecture/saving-states.html#restoring_complex_states_reassembling_the_pieces


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值