ViewModel和onSaveInstanceState

目前可能很多人已经使用了jetpack,目前,我已经完全将kotlin+jetpack用于项目中。项目开发完毕,现在回头看看一些技术细节。

onSaveInstanceState()

onSaveInstanceState()UI组件停止运行、且未被主动销毁时调用。如用户点击Home键跳转到桌面、用户跳转到新的UI组件,该UI组件停止运行。
若是主动销毁,onSaveInstanceState()不会被调用。如用户主动点击返回按钮、代码调用finish()相关的函数。

系统可能因内存过低、电量过低时回收在后台运行的UI组件(Activity/Fragment),用户重新打开该UI组件时,会恢复在onSaveInstanceState()保存的数据。

onSaveInstanceState()适合保存少量数据。具体能保存多少数据,我并没有在任何地方看见官方说的具体值,文章Saving UI state with ViewModel SavedState and Dagger
的作者Nimrod Dayan介绍说限制在1MB以下,尽可能是能够恢复界面数据的最小数据集。

ViewModel

ViewModel能够在配置更改时保留,如当屏幕旋转时,UI组件重新构建,重新得到的仍然是同一个ViewModelViewModel为何能在UI组件销毁时存活,可以看文章每日一问 Activity 都重建了,你 Fragment凭什么活着?

ViewModel可以保存更多的数据在内存中,这些数据通常是需要在UI上显示的。在配置更改时,UI组件只是临时地销毁,系统会立刻生成新的UI组件,之前存在的ViewModel会立即通知新的UI组件更新界面,这样界面看起来就和配置更改前完全一样了。

总结

虽然在配置更改时,ViewModel并不会重新创建,但是在系统回收UI组件时,ViewModel同样会被销毁,此时唯一能保存数据的只有onSaveInstanceState()(当然还可以持久化数据到文件/网络等)。

可以看出ViewModelonSaveInstanceState()的功能都是保存数据,但是他们在某种层面上是完全不同的:

  1. onSaveInstanceState()适合保存能够恢复UI组件的最小数据集;ViewModel保存UI组件显示所需的所有数据和一些额外的数据。
  2. ViewModel能够在配置更改时保留数据;onSaveInstanceState()能够在用户临时离开UI组件时保留数据。若需要用户在长时间离开UI组件时保存数据,请使用数据持久化。
  3. ViewModelonSaveInstanceState()并不冲突,反而应该结合使用。onSaveInstanceState()保存了恢复UI组件的最小数据,ViewModel需要这些数据重新恢复UI组件需要的其他数据。

显然,ViewModel在保存数据方面,解决了onConfigurationChanged()的问题,并没有解决onSaveInstanceState()的问题。

ViewModel和onSaveInstanceState()结合使用

在没有ViewModel之前,我们会将加载数据的逻辑放在UI组件中。UI组件启动需要的最少数据通常会保留在启动时传入的数据集中,如Activity启动时会在Intent中存储对应的数据。

若下次启动该Activity需要的最少数据没有任何修改,那么我们可以重复利用Intent,因为系统回收UI组件后重启该组件,系统会保留同样的Intent。此时我们就可以不使用onSaveInstanceState()

但是,若在UI组件存活时,更改过该组件启动需要的最小数据集,那么就不能使用Intent了。我们就应该在onSaveInstanceState()中保存最新的数据。

现代的组件架构会将业务逻辑放在ViewModel中,所以重新启动UI组件的最小数据集需要被传递给ViewModelViewModel依赖这些数据来加载恢复UI组件的更多数据。此时,我们就需要结合onSaveInstanceState()ViewModel使用了。

流程:

  1. ActivityIntent获取数据,或从onCreate(Bundle)中得到onSaveInstanceState()保存的数据
  2. 将这些数据赋值给ViewModel
  3. ViewModel使用这些数据加载UI组件显示的数据

上面的流程虽然没有任何问题,但是ViewModel的行为是完全依赖IntentonSaveInstanceState()的数据,它并没有将ViewModel和这些数据进行强绑定。

我们期望在构造ViewModel时就将这些数据传递给ViewModel使用。此时我们应该使用ViewModelProvider.Factory

如我们进入一个文章详情页面:

class ArticleDetailViewModel(private val id: Long) : ViewModel() {
    class Factory(private val id: Long) : ViewModelProvider.Factory() {
        override fun create(modelClass: Class<T>): T {
            return modelClass.getConstructor(Long::class.java).newInstance(id)
        }
    }

    private val _article = MutableLiveData<Article>()

    val article: LiveData<Article>
        get() = _article
    // ...
}

class ArticleDetailActivity: AppCompatActivity() {
    private val articleDetailViewModel: ArticleDetailViewModel by viewModels(factoryProducer = {
             ArticleDetailViewModel.Factory(intent.getLong("articleId", -1L))
         }
    )

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_article_detail)

        articleDetailViewModel.article.observe(this) { article ->
            // show article content
        }
        // ...
    }
}

这个文章详情页面依赖的最小数据集只有一个文章id。通过文章idViewModel加载文章的数据,UI组件观察到数据后进行显示。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容