Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/227.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android ViewModel在屏幕旋转时重新创建_Android_Android Architecture Components_Android Viewmodel - Fatal编程技术网

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

Android ViewModel在屏幕旋转时重新创建,android,android-architecture-components,android-viewmodel,Android,Android Architecture Components,Android Viewmodel,我发现架构组件ViewModel未被保留的情况——简言之,如下所示: 启动活动并创建ViewModel实例 活动被置于后台 设备屏幕旋转 活动被放回前台 调用ViewModel的onCleared方法并创建新对象 在这种情况下,我的ViewModel实例被破坏,这是Android的正常行为吗?如果是,是否有任何建议的保持其状态的解决方案 我能想到的一种方法是在调用onCleared后保存它,然而,每当活动实际完成时,它也会保持状态。另一种方法是使用onRestoreInstanceState,但

我发现架构组件
ViewModel
未被保留的情况——简言之,如下所示:

  • 启动活动并创建
    ViewModel
    实例
  • 活动被置于后台
  • 设备屏幕旋转
  • 活动被放回前台
  • 调用ViewModel的
    onCleared
    方法并创建新对象
  • 在这种情况下,我的
    ViewModel
    实例被破坏,这是Android的正常行为吗?如果是,是否有任何建议的保持其状态的解决方案

    我能想到的一种方法是在调用
    onCleared
    后保存它,然而,每当活动实际完成时,它也会保持状态。另一种方法是使用onRestoreInstanceState,但它会在每次屏幕旋转时启动(不仅仅是在应用程序处于后台时)


    处理这种情况的灵丹妙药是什么?

    AFAIK,
    ViewModel
    的唯一目的是在数据所有者经历不同的生命周期事件时保存数据(即“保存状态”)。所以你不必自己“拯救国家”

    我们可以从中看出这是“不正常的行为”
    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...
    });
    

    通过这样做,您应该会得到预期的效果。

    Yes@tomwyr,这是一个来自android框架的bug

    该修复程序有28.0.0-alpha3和AndroidX 1.0.0-alpha3版本

    但如果您现在不想更新到上述版本,那么您可以这样解决(我知道这是一个不好的解决方案,但我没有看到任何其他好方法

    在“活动”中,在调用super.ondestory之前,重写Onestory方法,并将所有必需字段保存到局部变量。现在调用super.ondestory,然后再次初始化ViewModel,并将所需字段分配回ViewModel的新实例

    关于

    以下代码在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)
    }
    

    将support library/compileSDK/targetSDK更改为28


    我有类似的问题,多窗口。切换到拆分屏幕时,将重新创建我的viewModel。支持库28修复了我的问题。(我的生命周期版本是1.1.1)

    对于像我这样的其他人来说,问题可能是您没有在工厂中正确设置ViewModelProvider

    在四处挖掘之后,我通过在活动中添加以下方法解决了类似的问题:

    protected final <T extends ViewModel> ViewModel obtainViewModel(@NonNull AppCompatActivity activity, @NonNull Class<T> modelClass) {
        ViewModelProvider.AndroidViewModelFactory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(activity.getApplication());
        return new ViewModelProvider(activity, factory).get(modelClass);
    }
    
    还是碎片

    private MyViewModel myViewModel;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getActivity() != null) {
            myViewModel = (MyViewModel) obtainFragmentViewModel(getActivity(), MyViewModel.class);
        }
    }
    

    到目前为止似乎效果不错。如果有人有更好的方法,请让我们知道

    是的,我完全按照您的示例创建它,即通过ViewModelProviders引用它。另外,如果你有兴趣的话,我在我的问题上加了一条评论。。对不起,这太糟糕了。如果这是一个已知的问题,那么我希望他们尽快解决。如果没有,那么希望有更有经验的人能启发我们,我认为目的是不同的。即使在某些情况下,当活动的生命周期结束时,它也能保存数据,就像在典型的轮换情况下一样。@Blcknx因此,我的回答中的“(并且没有被重新创建)”对我来说也是同样的问题,直到API级别26,它才能正常工作,但当我将API级别更新到27时,我遇到了这个问题,看起来这是Android框架的问题:。在这个SO问题中也报告了类似的问题:。我找到了一些其他方法来处理这个问题(做了一些代码更改,这样错误就不会影响我的应用程序),但您的解决方案似乎完全可以作为一种解决方法。
    private MyViewModel myViewModel;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        myViewModel = (MyViewModel) obtainViewModel(this, MyViewModel.class);
    }
    
    private MyViewModel myViewModel;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getActivity() != null) {
            myViewModel = (MyViewModel) obtainFragmentViewModel(getActivity(), MyViewModel.class);
        }
    }