ViewModel and SavedStateHandle: always retain state

栏目: IT技术 · 发布时间: 5年前

内容简介:I've written in the past aboutWell, not completely. There's a case that the ViewModel might get destroyed. That's theIf you don't do anything to handle this case, your app will just restart. If you want to resume the app to the state before it was killed,

I've written in the past about ViewModels initialization but what about ViewModel end of life? ViewModels famously solved the device orientation change problem. They don't get destroyed when changing between portrait <-> landscape orientations. So as long as you save the state in ViewModel (instead of the Activity/Fragment) you are safe, right?

Well, not completely. There's a case that the ViewModel might get destroyed. That's the system-initiated process death event case. When the system runs low on memory, it will start killing apps that are not in the foreground, starting from the least recently used. Users are switching between apps all the time. A common scenario, is for the user to launch your app, then to send it in the background to do something else, and then re-launch your app. Your app might be killed between the 2 launches.

If you don't do anything to handle this case, your app will just restart. If you want to resume the app to the state before it was killed, you would need to save that state somewhere.

You could either persist everything in local storage (which is an app architecture on its own) or use ViewModel's Saved State module . This is an extremely convenient way to resume the ViewModel's state when a system-initiated process death occurs.

Dependencies

Firstly, you would need an additional dependency , in addition to the core ViewModel. Add this to your build.gradle (check this to find the latest version).

[...]
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
build.gradle (app)

ViewModel without additional constructor parameters

If you have a ViewModel that doesn't have any constructor parameters, you can add a SavedStateHandle constructor parameter.

class MyViewModel(private val state: SavedStateHandle) : ViewModel() {
[...]
}

Then initiate as follow. The SavedStateHandle will be provided automatically by the viewModels delegated method.

override val model by viewModels<MyViewModel>()

ViewModel with constructor parameters

In case you are using a custom ViewModel factory (i.e. if you initiate your ViewModel with constructor parameters), then extend AbstractSavedStateViewModelFactory .

class MyViewModelFactory(owner: SavedStateRegistryOwner,
                                     private val myId: Int,
                                     defaultArgs: Bundle? = null
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {

    override fun <T : ViewModel?> create(
        key: String,
        modelClass: Class<T>,
        handle: SavedStateHandle
    ): T = MyViewModel(handle, myId) as T
}

Then retrieve your ViewModel as follow.

override val model by viewModels<MyViewModel> {
    MyViewModelFactory(this, args.myId)
}

How to use

For your LiveData needs, you probably used to creating your own MutableLiveData<T> instances. With the SavedStateHandle approach, you can acquire MutableLiveData<T> instances that will be retained even if the system kills your app process.

class MyViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {

    private val itemsLiveData = savedStateHandle.getLiveData<Item>("itemsKey")
    
    [...]
}

So each time state.getLiveData(KEY) is called with the same KEY, the same instance will be returned, even if the system kills the app process. Of course, for this to work everything that is stored in those LiveData must be Parcellable (in this case Item class must implement Parcelable , checkout @Parcelize annotation).

To test that the saving/restoration of your ViewModel works as expected, you can send your app to the background, kill it manually, and re-launch your app. Run the following command when your device is in the background to kill it.

adb shell am kill your.package.name

For anything not stored in a LiveData you want to retain, use savedStateHandle.set(KEY, VALUE) / savedStateHandle.get(KEY) (similar to a Map or Bundle ).

Don't forget that SavedStateHandle restores only the state of the current ViewModel . If your app is dependent on in-memory Singletons ( object in Kotlin) then you would need to take care of the restoration of those objects state yourself.

For additional reading on how to use the SavedStateHandle , check out the official doc and this codelab . Happy coding!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

网站运维技术与实践

网站运维技术与实践

饶琛琳 / 电子工业出版社 / 2014-3 / 69.00元

网站运维工作,一向以内容繁杂、覆盖面广著称。《网站运维技术与实践》选取日常工作涉及的监测调优、日志分析、集群规划、自动化部署、存储和数据库等方面,力图深入阐述各项工作的技术要点及协议原理,并介绍相关开源产品的实践经验。在技术之外,作者也分享了一些关于高效工作及个人成长方面的心得。 《网站运维技术与实践》适合Linux 系统管理员、中大型网站运维工程师及技术负责人、DevOps 爱好者阅读。同......一起来看看 《网站运维技术与实践》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

URL 编码/解码
URL 编码/解码

URL 编码/解码