5月26日,星期二。今天是第#414期Android Weekly的学习笔记。
ViewModel and SavedStatehandle: always retain state
https://www.rockandnull.com/viewmodel-savedstate/
一篇关于ViewModel数据恢复的小文。
进程清理和数据恢复
我们知道ViewModel可以解决诸如Orientation切换时,Activity/Fragment销毁重建的数据保存问题。然而,有时甚至连ViewModel自身也会被销毁,这种情况发生在应用位于后台且内存不足的情况下,系统会杀死进程。杀死进程的顺序是Least Recently Used (LRU)。
如果对此什么都不做的话,默认行为是重启App,如果想要在这个过程中重新恢复到App被清理前的页面,就必须通过类似onSaveInstanceState
的方法来保存数据。
对此,Jetpack提供了ViewModel’s Saved State module组件,通过它,可以方便地恢复ViewModel状态。
ViewModel-SaveState 的使用
通过gradle接入,在这里查看最新版本。
1 | implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version" |
不包含构造参数的ViewModel
在构造器里增加一个SavedStateHandle
类型的参数。
1 | class MyViewModel(private val state: SavedStateHandle) : ViewModel() { |
然后通过代理方式重写model
。
1 | override val model by viewModels<MyVioewModel> |
包含构造参数的ViewModel
对于包含参数的ViewModel(通过ViewModelFactory初始化),需要继承AbstractSavedStateViweModelFactory
类以实现SaveState功能。
1 | class MyViewModelFactory(owner: SavedStateRegistryOwner, |
然后在ViewModel里进行代理:
1 | override val model by viewModels<MyViewModel> { |
结合LiveData使用
通过Key-Value方式获取LiveData对象,而非直接构建。同一个Key往往会返回同一个Value,因为是持久化保存数据,Item
类必须实现Parcellable
接口,或者更简便地,通过@Parcelize
注解,关于Parcelize
可以阅读KEEP的这篇文章。
1 | class MyViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() { |
模拟低内存场景
- 启动你的APP
- 切换到后台
- 执行
adb shell am kill your.package.name
- 再次启动APP
注意SavedSateHandle
只能处理ViewModel中的数据,对于全局的静态单例,仍然需要通过人工的方式处理。
The Android Lifecycle cheat sheet — part IV : ViewModels, Translucent Activities and Launch Modes
https://medium.com/androiddevelopers/the-android-lifecycle-cheat-sheet-part-iv-49946659b094
Android Lifecycle cheat sheet 是Jose Alcerreca写的一系列生命周期总结文章,通过简单直观的图片表达。
第4期主要分析ViewModel、透明Activity和不同启动模式下的生命周期。
ViewModels
应用于Activity和Fragment,在onCreate
结束时初始化,在其销毁时销毁自身。
透明Activity
通过android:windowIsTranslucent
属性将Activity设定为透明,当在一个透明Activity上启动新的Activity时,原透明Activity只会执行onPause
,并不会onStop
,并且在他Pause的时候,还可以接受UI事件。
当按下Home键时,位于底层的透明Activity会进入onStop
状态,并且当用户切换回应用后,依次执行onRestart
和onStart
。
Launch Modes
关于启动模式的建议是——只使用默认的standard启动模式。更多细节可以参阅这篇文章:Tasks and Back Stack。
这是SINGLE_TOP
模式下的生命周期&栈情况。
然后是SINGLE_TASK
,再次强调,强烈不建议使用这种启动模式。
Understanding Kotlin Coroutines with this mental model
https://www.lukaslechner.com/understanding-kotlin-coroutines-with-this-mental-model/
什么是思维模型(Mental Model)
- 思维模型是我们理解世界的方式
- 我们通过思维模型将负责的事情简化
- 思维模型藐视事物如何运行
简单说,思维模型让我们知道How it works。
Routines
Coroutine由CO和ROUTINE两部分构成,Routine的概念是,一旦启动,就会执行完。而CO则为其赋予了并行的含义。
routine的运行方式如下,1和2顺序执行。
Coroutines
在调用后会立即返回,1和2的完成先后顺序不固定。
Coroutine内部调用suspend
函数的地方被称为“suspension point”,即中断点。
Coroutine思维模型要点
- Coroutine可以在调用后立即返回,在中断点中断后,过一段时间恢复
- 你可以通过Coroutine在不切换线程的情况下,执行并发任务,从而达到更高的运行效率
- Coroutine是线程之上的抽象,一个Coroutine内部的代码也可以运行在不同线程上
- 编译器将
suspend
函数转换为常规函数,同时增加一个Cotinuation
类型的参数,这是一种状态机 delay()
函数是非阻塞的,它使用类似handler.postDelayed()
的方式实现
Kotlin withContext vs Async-await
https://blog.mindorks.com/kotlin-withcontext-vs-async-await
最后一篇依然是关于Coroutine,作者介绍了两种启动协程的方式withContext
与async-await
的应用场景,守则如下。
- 它们都可以用来获取结果
- 不需要并行执行时,用
withContext
- 当且仅当需要并行时,用
async