[英]How ViewModel survives configuration change
I am trying to use ViewModel in my app.我正在尝试在我的应用程序中使用 ViewModel。 The question comes to my mind is How View Model survives configuration changes.
我想到的问题是 View Model 如何在配置更改中幸存下来。 I read number of blog posts saying that "
我读了很多博客文章说“
It will create a HolderFragment to add to your activity or your fragment, it's invisible, when the configuration changed, activity destroyed, but holder fragment is still alive
它将创建一个HolderFragment以添加到您的活动或片段中,它是不可见的,当配置更改时,活动被破坏,但持有者片段仍然存在
and that make sense.But I tried to explore more on this and found out that in support library 27.1.0+ they have removed the HolderFragment with Description saying这是有道理的。但我试图对此进行更多探索,发现在支持库 27.1.0+中,他们已经删除了带有描述的 HolderFragment 说
Deprecate ViewModelStores.of() and the HolderFragment it relies on as they are no longer needed link for android.googlesource .
弃用 ViewModelStores.of() 和它所依赖的 HolderFragment,因为它们不再需要android.googlesource 的链接。
Now the question is How they are doing the same thing right now?现在的问题是他们现在如何做同样的事情?
ViewModels created with ViewModelProviders.of()
method are stored in ViewModelStore
hashmap, so the real question is how ViewModelStore
is stored.使用
ViewModelProviders.of()
方法创建的 ViewModel 存储在ViewModelStore
hashmap 中,所以真正的问题是ViewModelStore
是如何存储的。
For activities, this logic is straightforward.对于活动,这个逻辑很简单。
ViewModelStore
is stored using onRetainNonConfigurationInstance
method: ViewModelStore
使用onRetainNonConfigurationInstance
方法存储:
@Override
@Nullable
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
// No one called getViewModelStore(), so see if there was an existing
// ViewModelStore from our last NonConfigurationInstance
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}
if (viewModelStore == null && custom == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
For fragments, things are a bit more complicated.对于片段,事情要复杂一些。
FragmentManagerImpl
now has a field called mNonConfig
: FragmentManagerImpl
现在有一个名为mNonConfig
的字段:
private FragmentManagerViewModel mNonConfig;
which stores a hashmap of a Fragment's UUID and a ViewModelStore
.它存储 Fragment 的 UUID 和
ViewModelStore
的 hashmap 。
This mNonConfig
field is initialized in FragmentManagerImpl#attachController
method:这个
mNonConfig
字段在FragmentManagerImpl#attachController
方法中初始化:
public void attachController(@NonNull FragmentHostCallback host,
@NonNull FragmentContainer container, @Nullable final Fragment parent) {
if (mHost != null) throw new IllegalStateException("Already attached");
mHost = host;
mContainer = container;
mParent = parent;
if (mParent != null) {
// Since the callback depends on us being the primary navigation fragment,
// update our callback now that we have a parent so that we have the correct
// state by default
updateOnBackPressedCallbackEnabled();
}
// Set up the OnBackPressedCallback
if (host instanceof OnBackPressedDispatcherOwner) {
OnBackPressedDispatcherOwner dispatcherOwner = ((OnBackPressedDispatcherOwner) host);
mOnBackPressedDispatcher = dispatcherOwner.getOnBackPressedDispatcher();
LifecycleOwner owner = parent != null ? parent : dispatcherOwner;
mOnBackPressedDispatcher.addCallback(owner, mOnBackPressedCallback);
}
// Get the FragmentManagerViewModel
if (parent != null) {
mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
} else if (host instanceof ViewModelStoreOwner) {
ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
} else {
mNonConfig = new FragmentManagerViewModel(false);
}
}
Basically, in order to retrieve a ViewModel
in Activity
one should call ViewModelProviders.of(this).get(SomeViewModel.class)
.基本上,为了在
Activity
中检索ViewModel
,应该调用ViewModelProviders.of(this).get(SomeViewModel.class)
。 Now, if we look into of
it looks like below:现在,如果我们查看它
of
如下所示:
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@Nullable Factory factory) {
Application application = checkApplication(activity);
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(activity.getViewModelStore(), factory);
}
So, the important part is this method - activity.getViewModelStore()
because it returns a wrapper object ( HashMap
holder) for all of your ViewModel
objects and if it can survive config changes so can all of your ViewModel
objects:因此,重要的部分是这个方法 -
activity.getViewModelStore()
因为它为所有ViewModel
对象返回一个包装器 object ( HashMap
持有者),如果它可以在配置更改中幸存下来,那么所有ViewModel
对象也可以:
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
mViewModelStore
will be either restored from NonConfigurationInstances
or created from scratch. mViewModelStore
将从NonConfigurationInstances
恢复或从头开始创建。 Pretty much, NonConfigurationInstances
is the object that survives config changes and hence is used to store the ViewModelStore
.几乎,
NonConfigurationInstances
是 object ,它在配置更改后仍然存在,因此用于存储ViewModelStore
。 That's why the same ViewModelStore
object is returned after rotation - it's stored in the config change independent NonConfigurationInstances
:这就是为什么旋转后返回相同的
ViewModelStore
object - 它存储在与配置更改无关的NonConfigurationInstances
:
If you look into onRetainNonConfigurationInstance()
, you will actually that your ViewModelStore
is saved there:如果您查看
onRetainNonConfigurationInstance()
,您实际上会发现您的ViewModelStore
保存在那里:
public final Object onRetainNonConfigurationInstance() {
...
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
Also, it will be cleared only if onDestroy
for a non-config change reason is called:此外,仅当出于非配置更改原因调用
onDestroy
时才会清除它:
...
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
...
A similar trick is used for storing a ViewModel
for a Fragment
.类似的技巧用于存储
Fragment
的ViewModel
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.