在某个时候,我注意到有关Google的架构组件中
ViewModel实际工作方式的定期讨论。 我意识到自己不了解,因此爬上了互联网,惊讶地发现,关于如何烹饪ViewModel,与LiveData交朋友,通过Dagger滑动依赖项,与RxJava交往以及其他各种有用程度的标题,有大量相同的文章,但是,里面发生的事情几乎没有。
因此,我将尝试自己填补空白。
注意事项
TL; DR,如果您为自己的时间感到抱歉-向下滚动至输出,您将损失很少。
因此,您需要注意的第一件事是,ViewModel有两个不同的体系结构组件包,即:
1)旧的
android.arch.lifecycle2)新的
androidx.lifecycle剧透 :它们之间没有太大区别。
所有工作都在于挑战:
ViewModelProviders.of(activity).get(MyViewModel::class.java)
让我们从of方法开始
public static ViewModelProvider of(@NonNull FragmentActivity activity) { return of(activity, null); } 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(ViewModelStores.of(activity), factory); }
checkApplication只是检查是否为null,而
AndroidViewModelFactory只是一个持有Application的线程安全单例。 因此它们并不是特别有趣,最有趣的是在
ViewModelStores.of方法中:
public static ViewModelStore of(@NonNull FragmentActivity activity) { if (activity instanceof ViewModelStoreOwner) { return ((ViewModelStoreOwner) activity).getViewModelStore(); } return holderFragmentFor(activity).getViewModelStore(); }
乍一看,它看起来很奇怪-为什么
FragmentActivity如果
已经实现了
ViewModelStoreOwner接口,为什么还要检查它是否存在? -并非总是如此-直到2018年2月,当
支持库版本
27.1.0发布时 ,FragmentActivity才从未实现ViewModelStoreOwner。 同时,ViewModel为自己工作。
因此,让我们从旧的案例开始
-holderFragmentFor方法已
启动 :
public static HolderFragment holderFragmentFor(FragmentActivity activity) { return sHolderFragmentManager.holderFragmentFor(activity); }
接下来,只需获取或创建一个新的
holder片段:
HolderFragment holderFragmentFor(FragmentActivity activity) { FragmentManager fm = activity.getSupportFragmentManager(); HolderFragment holder = findHolderFragment(fm); if (holder != null) { return holder; } holder = mNotCommittedActivityHolders.get(activity); if (holder != null) { return holder; } if (!mActivityCallbacksIsAdded) { mActivityCallbacksIsAdded = true; activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks); } holder = createHolderFragment(fm); mNotCommittedActivityHolders.put(activity, holder); return holder; }
好吧,
HolderFragment本身当然会
保留 public HolderFragment() { setRetainInstance(true); }
实际上,
ViewModelStore对象存储在其中,而该对象又包含一捆
ViewModel :
public class ViewModelStore { private final HashMap<String, ViewModel> mMap = new HashMap<>(); final void put(String key, ViewModel viewModel) { ViewModel oldViewModel = mMap.put(key, viewModel); if (oldViewModel != null) { oldViewModel.onCleared(); } } final ViewModel get(String key) { return mMap.get(key); } public final void clear() { for (ViewModel vm : mMap.values()) { vm.onCleared(); } mMap.clear(); } }
让我们回到支持库版本为27.1.0或更高版本的情况。 FragmentActivity已经实现了ViewModelStoreOwner接口,也就是说,它实现了唯一的
getViewModelStore方法:
public ViewModelStore getViewModelStore() { if (this.getApplication() == null) { throw new IllegalStateException("Your activity is not yet attached to the Application instance. You can't request ViewModel before onCreate call."); } else { if (this.mViewModelStore == null) { FragmentActivity.NonConfigurationInstances nc = (FragmentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance(); if (nc != null) { this.mViewModelStore = nc.viewModelStore; } if (this.mViewModelStore == null) { this.mViewModelStore = new ViewModelStore(); } } return this.mViewModelStore; } }
在这里,我将进行一些简化
-NonConfigurationInstances是一个不依赖于配置的对象(显然是名称),该对象位于
Activity中,并在
onStop和
onDestroy之间的重新创建期间通过
ActivityThread在
ActivityClientRecord内部进行扫描
总的来说,这看起来很有趣-开发人员做出了一个棘手的举动-而不是在
保留片段内部进行ViewModel传输的抢劫-他们使用了完全相同的机制,但是每次都无需创建额外的片段。
活动始终具有有趣的
onRetainNonConfigurationInstance方法。 在活动课上,他基本上什么也没做。 一般而言:
public Object onRetainNonConfigurationInstance() { return null; }
文档中的描述很有希望:
当已知将立即为新配置创建新实例时,由系统调用,作为由于配置更改而破坏活动的一部分。 您可以在此处返回任何您喜欢的对象,包括活动实例本身,以后可以通过在新活动实例中调用getLastNonConfigurationInstance()来检索该对象。

也就是说,不要放置在其中的内容-重新创建Activity后,它将在
getLastNonConfigurationInstance()中爬出。 架构组件的开发人员利用了这一优势。 缺点-最多4个android不能正常工作,必须通过保留片段以老式方式完成。
ViewModel的
clear()方法非常简单-在
onDestroy FragmentActivity方法中。
protected void onDestroy() { super.onDestroy(); if (this.mViewModelStore != null && !this.isChangingConfigurations()) { this.mViewModelStore.clear(); } this.mFragments.dispatchDestroy(); }
实际上,对于Androidx,几乎所有内容都是相同的,唯一的区别是,getViewModelStore()方法不再是FragmentActivity中的,而不再是
ComponentActivity中的 ,Activity在AndroidX中继承了FragmentActivity。 仅对clear()方法的调用已更改;已将其从onDestroy移至独立的回调,该回调在ComponentActivity构造函数中创建:
getLifecycle().addObserver(new GenericLifecycleObserver() { @Override public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) { if (event == Lifecycle.Event.ON_DESTROY) { if (!isChangingConfigurations()) { getViewModelStore().clear(); } } } });
对于协议-在创建文章期间使用了以下内容:
支持库27.0.0,28.0.0
androidx.lifecycle:lifecycle-viewmodel:2.0.0
androidx.lifecycle:生命周期扩展:2.0.0
android.arch.lifecycle:扩展:1.1.1
android.arch.lifecycle:视图模型:1.1.1
结论:
-ViewModel确实在
保留片段的活动恢复后幸存下来,直到2018年2月出现的Support库27.1.0
-从
支持库版本
27.1.0起,以及从
AndroidX ViewModel开始,我都等待着在
FragmentActivity.NonConfigurationInstances (适用于AndroidX的
ComponentActivity.NonConfigurationInstances )中重新创建Activity,实际上,保留片段的工作原理相同,但是不需要创建额外的片段,所有ViewModel都会与保留片段一起“发送到”。
-AndroidX和支持库中ViewModel的机制几乎
相同-如果您突然需要(是的,我无法想象为什么)拖动应在Activity生存期间
保留的数据,但
要考虑到娱乐性-您可以使用
onRetainNonConfigurationInstance() /
getLastNonConfigurationInstance()-有记录的黑客行为和拐杖之间的旧决定,新决定是什么