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
实例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);
}
}