Android ViewModel如何经受配置更改
我正在尝试在我的应用程序中使用ViewModel。我想到的问题是视图模型如何经受住配置更改。我读了很多博客帖子,上面说“ 它将创建一个HolderFragment,添加到您的活动或活动中 片段,它是不可见的,当配置更改时,活动 摧毁,但持有者碎片仍然活着 这是有道理的。但是我试图对此进行更多的探索,发现在支持库27.1.0+中,他们删除了HolderFragment,并使用了描述 弃用ViewModelStores.of()及其所依赖的HolderFragment 因为不再需要它们Android ViewModel如何经受配置更改,android,mvvm,android-architecture-components,android-viewmodel,Android,Mvvm,Android Architecture Components,Android Viewmodel,我正在尝试在我的应用程序中使用ViewModel。我想到的问题是视图模型如何经受住配置更改。我读了很多博客帖子,上面说“ 它将创建一个HolderFragment,添加到您的活动或活动中 片段,它是不可见的,当配置更改时,活动 摧毁,但持有者碎片仍然活着 这是有道理的。但是我试图对此进行更多的探索,发现在支持库27.1.0+中,他们删除了HolderFragment,并使用了描述 弃用ViewModelStores.of()及其所依赖的HolderFragment 因为不再需要它们 现在的问题是
现在的问题是他们现在是如何做同样的事情的?使用
ViewModelProviders.of()
方法创建的ViewModels存储在ViewModelStore
hashmap中,所以真正的问题是如何存储ViewModelStore
对于活动,此逻辑非常简单。ViewModelStore
使用onretainonconfigurationinstance
方法存储:
@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;
}
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);
}
}
对于片段,事情要复杂一些。FragmentManagerImpl
现在有一个名为mNonConfig
的字段:
private FragmentManagerViewModel mNonConfig;
它存储片段的UUID的hashmap和ViewModelStore
此mNonConfig
字段在FragmentManagerImpl#attachController
方法中初始化:
@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;
}
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);
}
}
基本上,为了在
活动中检索ViewModel
,应该调用ViewModelProviders.of(this).get(SomeViewModel.class)
。现在,如果我们查看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);
}
因此,重要的部分是这个方法-activity.getViewModelStore()
,因为它为所有ViewModel
对象返回一个包装器对象(HashMap
holder),如果它能够在配置更改后存活,那么所有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
将从NonConfigurationInstances
还原或从头创建。基本上,NonConfigurationInstances
是在配置更改后仍然存在的对象,因此用于存储ViewModelStore
。这就是返回相同ViewModelStore
对象的原因ter rotation-它存储在独立于配置更改的非配置实例中
:
如果查看onretainonconfigurationinstance()
,实际上会发现您的ViewModelStore
保存在那里:
public final Object onRetainNonConfigurationInstance() {
...
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
此外,仅当调用非配置更改原因的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();
}
}
}
});
...
类似的技巧用于存储片段的视图模型
,很好的答案,但是OnRetainonConfiguration实例
在API 15中不是被去除了吗?