首页 文章

Android ViewModel在屏幕旋转时重新创建

提问于
浏览
3

我发现了一个不保留架构组件ViewModel的情况 - 简而言之,它如下:

  • 活动已启动,并且已创建ViewModel实例

  • 活动被放到后台

  • 设备屏幕旋转

  • 活动被放回前台

  • 调用ViewModel的 onCleared 方法并创建新对象

在这种情况下,我的ViewModel实例正在被销毁,这是Android的正常行为吗?如果是这样,是否有任何建议的解决方案来保持其状态?
我能想到的一种方法是在调用 onCleared 时保存它,但是,只要活动实际完成,它也会保持状态 . 另一种方法可能是使用 onRestoreInstanceState ,但它会在每个屏幕旋转时触发(不仅仅是应用程序在后台) .
处理这种情况的银弹?

2 回答

  • 0

    是的@tomwyr,这是一个来自android框架的bug . Bug details

    该修复程序在28.0.0-alpha3和AndroidX 1.0.0-alpha3中可用

    但如果您现在不想更新到上面的版本,那么您可以像这样解决( I know this is a bad solution but I didn't see any other good way

    在您的活动中覆盖 onDestroy method 并将所有必填字段保存到本地变量 before calling super.onDestroy . 现在调用super.onDestroy,然后再次初始化ViewModel,并将所需的字段分配回ViewModel的新实例

    关于isFinishing

    Below code is in Kotlin

    override fun onDestroy() {
         val oldViewModel = obtainViewModel()
    
         if (!isFinishing) { //isFinishing will be false in case of orientation change
    
              val requiredFieldValue = oldViewModel.getRequiredFieldValue()
    
              super.onDestroy
    
             val newViewModel = obtainViewModel()
    
             if (newViewModel != oldViewModel) { //View Model has been destroyed
                  newViewModel.setRequiredFieldValue(requiredFieldValue)
              }
          } else {
             super.onDestroy
          }
     }
    
    private fun obtainViewModel(): SampleViewModel {
          return ViewModelProviders.of(this).get(SampleViewModel::class.java)
    }
    
  • 5

    AFAIK, ViewModel 's only purpose is to survive and keep the data (i.e. 342386 ) while its owner goes through different lifecycle events. So you don' t必须自己"save the state" .

    我们可以从中看出它是"not normal behavior" . onCleared() 仅在活动结束后调用(并且不会再次重新创建) .

    您是使用 ViewModelProvider 创建 ViewModel ,还是使用构造函数创建实例?

    在你的活动中,你应该有类似的东西:

    // in onCreate() - for example - of your activity
    model = ViewModelProviders.of(this).get(MyViewModel.class);
    // then use it anywhere in the activity like so
    model.someAsyncMethod().observe(this, arg -> {
        // do sth...
    });
    

    通过这样做,你应该得到预期的效果 .

相关问题