我正在尝试在我的应用中使用ViewModel。我想到的问题是, View 模型如何在配置更改中生存下来。我读了许多博客文章,内容是:
但我尝试对此进行更多探索,发现在支持库27.1.0+ 中,他们已删除了HolderFragment,并带有Description字样
现在的问题是,他们现在如何做同样的事情?
最佳答案
用ViewModelProviders.of()
方法创建的ViewModel存储在ViewModelStore
哈希图中,因此真正的问题是ViewModelStore
的存储方式。
对于 Activity ,此逻辑很简单。 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;
}
对于 fragment ,情况要复杂一些。
FragmentManagerImpl
现在有一个名为mNonConfig
的字段:private FragmentManagerViewModel mNonConfig;
它存储Fragment的UUID和
ViewModelStore
的哈希图。此
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);
}
}