[关闭]
@TryLoveCatch 2021-04-08T12:07:51.000000Z 字数 19080 阅读 1127

Jetpack之ViewModel

android Jetpack ViewModel


ViewModelProviders

作用

https://toutiao.io/posts/hd57u6/preview

用法

自定义ViewModel

  1. public class AViewModel extends ViewModel {
  2. private MutableLiveData<User> userLiveData = new MutableLiveData<User>();
  3. public LiveData getUser(){
  4. //获取数据
  5. loadData();
  6. return userLiveData;
  7. }
  8. private void loadData(){
  9. new Thread(){
  10. @Override
  11. public void run() {
  12. // postValue: 接收端在主线程回调数据。
  13. // setValue: 接收端数据回调与发送端同一个线程。
  14. userLiveData.postValue(new User());
  15. }
  16. }.start();
  17. }
  18. public LiveData getDatas(){
  19. return userLiveData;
  20. }
  21. public void updateUser(){
  22. loadData();
  23. }
  24. }

ViewModel里面不要有Andrid库相关的类,例如context等

在Activity中使用

  1. public class ActivityA extends AppCompatActivity {
  2. //...
  3. ViewModelProviders.of(ActivityA.this).get(AViewModel.class)
  4. .getUser().observe(this, new Observer<User>() {
  5. @Override
  6. public void onChanged(@Nullable User user) {
  7. //获取数据变化
  8. }
  9. });
  10. }

需要传入Activity

在Fragment中创建使用ViewModel

ViewModel只会在Activity存活时,只会创建一次,因此
在同一个Activity中可以在多个Fragment中共享ViewModel中数据。

  1. public class FragmentA extends Fragment{
  2. //...
  3. ViewModelProviders.of(getActivity()).get(AViewModel.class).getDatas().observe(this, new Observer<User>() {
  4. @Override
  5. public void onChanged(@Nullable User user) {
  6. //获取Activity中数据变化
  7. }
  8. });
  9. }
  1. public class FragmentB extends Fragment{
  2. //...
  3. ViewModelProviders.of(getActivity()).get(AViewModel.class).getDatas().observe(this, new Observer<User>() {
  4. @Override
  5. public void onChanged(@Nullable User user) {
  6. //获取Activity中数据变化
  7. }
  8. });
  9. }

AndroidViewModel

  1. public class AndroidViewModel extends ViewModel {
  2. @SuppressLint("StaticFieldLeak")
  3. private Application mApplication;
  4. public AndroidViewModel(@NonNull Application application) {
  5. mApplication = application;
  6. }
  7. /**
  8. * Return the application.
  9. */
  10. @SuppressWarnings("TypeParameterUnusedInFormals")
  11. @NonNull
  12. public <T extends Application> T getApplication() {
  13. //noinspection unchecked
  14. return (T) mApplication;
  15. }
  16. }

提供了Application

源码

基于android.arch.lifecycle的1.1.1版本

下图说明了Activity经历屏幕旋转直到最终destroyed掉这整个过程中所经历的各个生命周期。该图还在关联的Activity生命周期的旁边显示了ViewModel的生命周期。

我们可以看出,ViewModel的生命周期贯穿Activity始终,直到Activity正常结束,并不会因为屏幕旋转等系统原因而导致ViewModel生命周期提前结束。同理Fragment对于ViewModel也一样。

ViewModelProviders

我们从使用的入口函数一步一步来看:

  1. ViewModelProviders.of(getActivity()).get(AViewModel.class)
  1. @NonNull
  2. @MainThread
  3. public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
  4. Application application = checkApplication(checkActivity(fragment));
  5. if (factory == null) {
  6. factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
  7. }
  8. return new ViewModelProvider(ViewModelStores.of(fragment), factory);
  9. }
  10. @NonNull
  11. @MainThread
  12. public static ViewModelProvider of(@NonNull FragmentActivity activity,
  13. @Nullable Factory factory) {
  14. Application application = checkApplication(activity);
  15. if (factory == null) {
  16. factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
  17. }
  18. return new ViewModelProvider(ViewModelStores.of(activity), factory);
  19. }

先去得到Application,因为我们调用的时候of()的是一个参数方法,所以factory肯定为null,关于factory后面在说,我们继续看。
这里需要注意的是,既然factory可以由外部来传入,所以我们可以不使用系统的反射factory,可以来定制自己的factory,只需要实现create方法就行了

ViewModelStores

在new ViewModelProvider的时候,先调用ViewModelStores.of(),我们看下源码:

  1. public class ViewModelStores {
  2. private ViewModelStores() {
  3. }
  4. /**
  5. * Returns the {@link ViewModelStore} of the given activity.
  6. *
  7. * @param activity an activity whose {@code ViewModelStore} is requested
  8. * @return a {@code ViewModelStore}
  9. */
  10. @NonNull
  11. @MainThread
  12. public static ViewModelStore of(@NonNull FragmentActivity activity) {
  13. if (activity instanceof ViewModelStoreOwner) {
  14. return ((ViewModelStoreOwner) activity).getViewModelStore();
  15. }
  16. return holderFragmentFor(activity).getViewModelStore();
  17. }
  18. /**
  19. * Returns the {@link ViewModelStore} of the given fragment.
  20. *
  21. * @param fragment a fragment whose {@code ViewModelStore} is requested
  22. * @return a {@code ViewModelStore}
  23. */
  24. @NonNull
  25. @MainThread
  26. public static ViewModelStore of(@NonNull Fragment fragment) {
  27. if (fragment instanceof ViewModelStoreOwner) {
  28. return ((ViewModelStoreOwner) fragment).getViewModelStore();
  29. }
  30. return holderFragmentFor(fragment).getViewModelStore();
  31. }
  32. }

ViewModelStores代码很简单,类似于ViewModelProviders,看代码可知,就是从Activity或者Fragment里面获取ViewModelStore,然后传给ViewModelProvider。
一般来说,我们都是走了holderFragmentFor(),会返回一个HolderFragment,我们的ViewModelStore是通过HolderFragment#getViewModelStore()来获取的,在后面我们会单独来说下这个HolderFragment

ViewModelProvider

  1. public static ViewModelProvider of(@NonNull FragmentActivity activity,
  2. @Nullable Factory factory) {
  3. Application application = checkApplication(activity);
  4. if (factory == null) {
  5. factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
  6. }
  7. return new ViewModelProvider(ViewModelStores.of(activity), factory);
  8. }

得到ViewModelProvider之后,就会调用它的get()方法:

  1. public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
  2. String canonicalName = modelClass.getCanonicalName();
  3. if (canonicalName == null) {
  4. throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
  5. }
  6. return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
  7. }
  8. public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
  9. ViewModel viewModel = mViewModelStore.get(key);
  10. if (modelClass.isInstance(viewModel)) {
  11. //noinspection unchecked
  12. return (T) viewModel;
  13. } else {
  14. //noinspection StatementWithEmptyBody
  15. if (viewModel != null) {
  16. // TODO: log a warning.
  17. }
  18. }
  19. viewModel = mFactory.create(modelClass);
  20. mViewModelStore.put(key, viewModel);
  21. //noinspection unchecked
  22. return (T) viewModel;
  23. }

先来看key,得到了传入ViewModel的canonicalName:

  1. getName com.test.TestClass
  2. getCanonicalName com.test.TestClass
  3. getSimpleName TestClass
  4. getName com.test.TestClass$TestInnerClass
  5. getCanonicalName com.test.TestClass.TestInnerClass
  6. getSimpleName TestInnerClass
  7. getName [Lcom.test.TestClass$TestInnerClass;
  8. getCanonicalName com.test.TestClass.TestInnerClass[]
  9. getSimpleName TestInnerClass[]

然后根据这个key,从ViewModelStore里面去获取ViewModel:

  1. ViewModel viewModel = mViewModelStore.get(key);

ViewModelStore

我们来看一下ViewModelStore的代码:

  1. public class ViewModelStore {
  2. private final HashMap<String, ViewModel> mMap = new HashMap<>();
  3. final void put(String key, ViewModel viewModel) {
  4. ViewModel oldViewModel = mMap.put(key, viewModel);
  5. if (oldViewModel != null) {
  6. oldViewModel.onCleared();
  7. }
  8. }
  9. final ViewModel get(String key) {
  10. return mMap.get(key);
  11. }
  12. /**
  13. * Clears internal storage and notifies ViewModels that they are no longer used.
  14. */
  15. public final void clear() {
  16. for (ViewModel vm : mMap.values()) {
  17. vm.onCleared();
  18. }
  19. mMap.clear();
  20. }
  21. }

ViewModelStore里面只有一个Map,就是一个ViewModel和className对应的缓存
然后,如果我们得到的这个ViewModel,就是传入modelClass的实例的话,就直接返回,否则,呃,并没有实现,只有一个空的if。。

AndroidViewModelFactory

  1. public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
  2. private static AndroidViewModelFactory sInstance;
  3. /**
  4. * Retrieve a singleton instance of AndroidViewModelFactory.
  5. *
  6. * @param application an application to pass in {@link AndroidViewModel}
  7. * @return A valid {@link AndroidViewModelFactory}
  8. */
  9. @NonNull
  10. public static AndroidViewModelFactory getInstance(@NonNull Application application) {
  11. if (sInstance == null) {
  12. sInstance = new AndroidViewModelFactory(application);
  13. }
  14. return sInstance;
  15. }
  16. private Application mApplication;
  17. /**
  18. * Creates a {@code AndroidViewModelFactory}
  19. *
  20. * @param application an application to pass in {@link AndroidViewModel}
  21. */
  22. public AndroidViewModelFactory(@NonNull Application application) {
  23. mApplication = application;
  24. }
  25. @NonNull
  26. @Override
  27. public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
  28. if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
  29. //noinspection TryWithIdenticalCatches
  30. try {
  31. return modelClass.getConstructor(Application.class).newInstance(mApplication);
  32. } catch (NoSuchMethodException e) {
  33. throw new RuntimeException("Cannot create an instance of " + modelClass, e);
  34. } catch (IllegalAccessException e) {
  35. throw new RuntimeException("Cannot create an instance of " + modelClass, e);
  36. } catch (InstantiationException e) {
  37. throw new RuntimeException("Cannot create an instance of " + modelClass, e);
  38. } catch (InvocationTargetException e) {
  39. throw new RuntimeException("Cannot create an instance of " + modelClass, e);
  40. }
  41. }
  42. return super.create(modelClass);
  43. }
  44. }

可以看出来AndroidViewModelFactory是一个单例,构造函数的参数也是Application,所以可以确定factory是唯一的。
我们创建的是AndroidViewModelFactory,继承自NewInstanceFactory,NewInstanceFactory里面是直接默认构造函数创建ViewModel,而AndroidViewModelFactory会使用一个参数Application的构造函数来创建AndroidViewModel。

为什么要加混淆

很简单,因为用到来反射,所以会增加keep:

  1. -keep class android.arch.lifecycle.** { *; }
  2. -keep class android.arch.core.internal.SafeIterableMap { *; }

HolderFragment

https://www.mdeditor.tw/pl/2QxK
HolderFragment是保证ViewModel在屏幕旋转等系统销毁之后,保持唯一的核心方法。
ViewModel 对生命周期的管理与 Glide 和 RxPermission 等框架的处理方式一致,就是使用一个空的 Fragment 来进行生命周期管理。
利用无View的HolderFragment,使用setRetainInstance(true)保证其在config change时不被销毁

  1. public class HolderFragment extends Fragment implements ViewModelStoreOwner {
  2. private static final String LOG_TAG = "ViewModelStores";
  3. // 这是什么?请看下面注释分析
  4. private static final HolderFragmentManager sHolderFragmentManager = new HolderFragmentManager();
  5. @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
  6. public static final String HOLDER_TAG = "android.arch.lifecycle.state.StateProviderHolderFragment";
  7. // 这就是我们存放 ViewModel 的 ViewModelStore,就定义在 HolderFragment里
  8. private ViewModelStore mViewModelStore = new ViewModelStore();
  9. public HolderFragment() {
  10. // 划重点啦!!!为什么当 activity 由于屏幕旋转等被系统销毁时,
  11. // 这个 fragment 实例也不会被销毁?因为设置了 setRetainInstance(true)
  12. setRetainInstance(true);
  13. }
  14. @Override
  15. public void onCreate(@Nullable Bundle savedInstanceState) {
  16. super.onCreate(savedInstanceState);
  17. // 当 Fragment 的 onCreate 方法执行,说明了 Fragment 已经成功添加到了 Activity,
  18. // sHolderFragmentManager 是 HolderFragmentManager类,它的 holderFragmentCreated()方法
  19. // 是将该 Fragment 从 mNotCommittedActivityHolders 或 mNotCommittedFragmentHolders 中移除
  20. // (HolderFragmentManager 的说明,请看下面的注释)
  21. sHolderFragmentManager.holderFragmentCreated(this);
  22. }
  23. @Override
  24. public void onSaveInstanceState(Bundle outState) {
  25. super.onSaveInstanceState(outState);
  26. }
  27. @Override
  28. public void onDestroy() {
  29. super.onDestroy();
  30. // 当一个设置了 setRetainInstance(true) 的 Fragment 的 onDestroy 方法被调用,
  31. // 证明它依附的 Activity 已经寿终正寝,所以调用 mViewModelStore.clear(),
  32. // 前面我们已经说了,这个 clear 方法会调用所有 ViewModel 对象的 onCleared 方法
  33. // 并且清空它们,我们可以在 ViewModel 的onCleared 方法做一些处理,以免起来不必要的
  34. // 内存泄漏等问题
  35. mViewModelStore.clear();
  36. }
  37. // 该方法用于给外部调用,返回 ViewModelStore
  38. @Override
  39. public ViewModelStore getViewModelStore() {
  40. return mViewModelStore;
  41. }
  42. // 静态方法,没 ViewModelStores.of 方法中被调用
  43. // 作用:在 activity 中添加一个 HolderFragment 用于存储存放了ViewModel对象的ViewModelStore
  44. public static HolderFragment holderFragmentFor(FragmentActivity activity) {
  45. return sHolderFragmentManager.holderFragmentFor(activity);
  46. }
  47. // 静态方法,没 ViewModelStores.of 方法中被调用
  48. // 作用:在 fragment 中添加一个 HolderFragment 用于存储存放了ViewModel对象的ViewModelStore
  49. @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
  50. public static HolderFragment holderFragmentFor(Fragment fragment) {
  51. return sHolderFragmentManager.holderFragmentFor(fragment);
  52. }
  53. // 上面的大部分操作都是基于HolderFragmentManager,我们来分析下这个类
  54. @SuppressWarnings("WeakerAccess")
  55. static class HolderFragmentManager {
  56. // 存放还没被系统正式添加到 Activity 中的 HolderFragment
  57. private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>();
  58. private Map<Fragment, HolderFragment> mNotCommittedFragmentHolders = new HashMap<>();
  59. // 声明定义了一个能够感知 Activity 生命周期的 ActivityLifecycleCallbacks
  60. private ActivityLifecycleCallbacks mActivityCallbacks =
  61. new EmptyActivityLifecycleCallbacks() {
  62. @Override
  63. public void onActivityDestroyed(Activity activity) {
  64. // 当 Activity destroy 的时候,清除 mNotCommittedActivityHolders 中保存
  65. // 的对应 HolderFragment。前面我们分析了 HolderFragment 的 onCreate 方法中
  66. // 会请一次 mNotCommittedActivityHolders,为什么在这么还要多此一举呢?其实
  67. // 并不是多此一举,因为 Fragment 有可能还没创建完,Activity 就夭折了,那这样子
  68. // HodlerFragment 的 onCreate 就无法调用,所以在加多一层清理机制,确保能够
  69. // 清除掉(不得不感叹,谷歌官方的严谨以及对源码的掌控理解能力)
  70. HolderFragment fragment = mNotCommittedActivityHolders.remove(activity);
  71. if (fragment != null) {
  72. Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity);
  73. }
  74. }
  75. };
  76. private boolean mActivityCallbacksIsAdded = false;
  77. private FragmentLifecycleCallbacks mParentDestroyedCallback =
  78. new FragmentLifecycleCallbacks() {
  79. @Override
  80. public void onFragmentDestroyed(FragmentManager fm, Fragment parentFragment) {
  81. // 与 mActivityCallbacks 的分析同理
  82. super.onFragmentDestroyed(fm, parentFragment);
  83. HolderFragment fragment = mNotCommittedFragmentHolders.remove(
  84. parentFragment);
  85. if (fragment != null) {
  86. Log.e(LOG_TAG, "Failed to save a ViewModel for " + parentFragment);
  87. }
  88. }
  89. };
  90. // HolderFragment 的 onCreate 生命周期被回调,就会调用这个方法,清除
  91. // mNotCommittedActivityHolders 或者 mNotCommittedFragmentHolders 中
  92. // 的引用的 HolderFragment
  93. void holderFragmentCreated(Fragment holderFragment) {
  94. Fragment parentFragment = holderFragment.getParentFragment();
  95. if (parentFragment != null) {
  96. mNotCommittedFragmentHolders.remove(parentFragment);
  97. parentFragment.getFragmentManager().unregisterFragmentLifecycleCallbacks(
  98. mParentDestroyedCallback);
  99. } else {
  100. mNotCommittedActivityHolders.remove(holderFragment.getActivity());
  101. }
  102. }
  103. private static HolderFragment findHolderFragment(FragmentManager manager) {
  104. if (manager.isDestroyed()) {
  105. throw new IllegalStateException("Can't access ViewModels from onDestroy");
  106. }
  107. Fragment fragmentByTag = manager.findFragmentByTag(HOLDER_TAG);
  108. if (fragmentByTag != null && !(fragmentByTag instanceof HolderFragment)) {
  109. throw new IllegalStateException("Unexpected "
  110. + "fragment instance was returned by HOLDER_TAG");
  111. }
  112. return (HolderFragment) fragmentByTag;
  113. }
  114. private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
  115. HolderFragment holder = new HolderFragment();
  116. fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
  117. return holder;
  118. }
  119. HolderFragment holderFragmentFor(FragmentActivity activity) {
  120. FragmentManager fm = activity.getSupportFragmentManager();
  121. HolderFragment holder = findHolderFragment(fm);
  122. if (holder != null) {
  123. return holder;
  124. }
  125. holder = mNotCommittedActivityHolders.get(activity);
  126. if (holder != null) {
  127. return holder;
  128. }
  129. if (!mActivityCallbacksIsAdded) {
  130. mActivityCallbacksIsAdded = true;
  131. activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
  132. }
  133. holder = createHolderFragment(fm);
  134. // 我们新添加 add 的 Fragment 并不会马上就执行添加完(也就是说,这个方法执行完成后,马上再
  135. // 调用一次,上面的 findHolderFragment 会返回 null。但是这没有关系,因为接下来我们还可
  136. // 从 mNotCommittedActivityHolders 获取到对应的实例),所以我们这里先把他放在
  137. // mNotCommittedActivityHolders 中。Not Committed 表示 fragment 的 commit 还没有完成
  138. mNotCommittedActivityHolders.put(activity, holder);
  139. return holder;
  140. }
  141. HolderFragment holderFragmentFor(Fragment parentFragment) {
  142. FragmentManager fm = parentFragment.getChildFragmentManager();
  143. HolderFragment holder = findHolderFragment(fm);
  144. if (holder != null) {
  145. return holder;
  146. }
  147. holder = mNotCommittedFragmentHolders.get(parentFragment);
  148. if (holder != null) {
  149. return holder;
  150. }
  151. parentFragment.getFragmentManager().registerFragmentLifecycleCallbacks(mParentDestroyedCallback, false);
  152. holder = createHolderFragment(fm);
  153. // 同上
  154. mNotCommittedFragmentHolders.put(parentFragment, holder);
  155. return holder;
  156. }
  157. }
  158. }

setRetainInstance

https://blog.csdn.net/Gaugamela/article/details/56280384

Fragment具有属性retainInstance,默认值为false。

  • false: 当设备旋转时,fragment会随托管activity一起销毁并重建。
  • true: 当设备旋转时,fragment不会随着activity一起被销毁,它会一直保留(进程不消亡的前提下),并在需要时原封不动地传递给新的Activity。

示例代码如下:

  1. @Override
  2. public void onCreate(Bundle savedInstanceState) {
  3. super.onCreate(savedInstanceState);
  4. setRetainInstance(true);
  5. ...........
  6. }

虽然保留的fragment没有被销毁,但它已脱离消亡中的activity并处于保留状态。
尽管此时的fragment仍然存在,但已经没有任何activity托管它,其生命周期如下图所示:

小结

生命周期

HolderFragment掌控了ViewModel的生命周期。

创建

销毁

ViewModelProvider每次都是new的,里面只持有了ViewModelStore,而我们的ViewModel是存在ViewModelStore中的,所以我们需要关心ViewModelStore是什么时候释放的?

  1. public class ViewModelStore {
  2. private final HashMap<String, ViewModel> mMap = new HashMap<>();
  3. /**
  4. * Clears internal storage and notifies ViewModels that they are no longer used.
  5. */
  6. public final void clear() {
  7. for (ViewModel vm : mMap.values()) {
  8. vm.onCleared();
  9. }
  10. mMap.clear();
  11. }
  12. }

可以看到ViewModelStore里面有一个clear方法:

那么是什么时候调用的呢?

  1. @Override
  2. public void onDestroy() {
  3. super.onDestroy();
  4. mViewModelStore.clear();
  5. }

是在implements ViewModelStoreOwner的onDestroy()里面调用的,其实大多数时候,就是在HolderFragment#onDestroy()里面调用的。

小结

是否全局唯一 备注
ViewModelProviders 全是静态方法
Factory 如何创建ViewModel,AndroidViewModelFactory 继承自NewInstanceFactory
HolderFragment 不是 大体跟Activity生命周期一致,但是在屏幕旋转等被系统销毁时,它不会被销毁
ViewModelStores 全是静态方法
ViewModelStore 不是 从HolderFragment里面获取,所以生命周期应该与其一致,它只是一个HashMap的缓存,缓存了className和ViewModel
ViewModelProvider 不是 ViewModelProviders#of()每次都会new一个新的
ViewModel 不是 先从ViewModelStore里面获取,如果没有就从Factory里面通过反射获取,一般来说同一个Activity多个get,得到也是同一个ViewModel


回答几个问题:

ViewModel以及存储在其中的数据是怎样在屏幕旋转下依然保留在内存中的?

GC垃圾回收机制不会回收被强引用的对象。在开发过程中,我们需要存储的数据被ViewModel引用,ViewModel被ViewModelStore引用,而ViewModelStore又被HolderFragment引用,于是就形成了一条引用链:HolderFragment->ViewModelStore->ViewModel->我们想要存储的数据(最佳实践是LiveData)。通过上面HolderFragment的分析,我们知道HodlerFragment在创建时,设置了setRetainInstance(true),因此它使得自身能够不受到屏幕旋转等configuration changes影响而存活,直到依附的Activity正常结束。

ViewModel和LiveData

https://juejin.cn/post/6844903975133642759

1、理想情况下,ViewModel 应该对 Android 世界一无所知。这提升了可测试性,内存泄漏安全性,并且便于模块化。
通常的做法是保证你的 ViewModel 中没有导入任何 android.*(android.arch.* 除外)。

2、View 通常是不进行单元测试的,除非你使用了 Robolectric,所以其中的代码越少越好。 View 只需要知道如何展示数据以及向 ViewModel/Presenter 发送用户事件。

3、ViewModel 和 Activity/Fragment
具有不同的作用域。当 ViewModel 进入 alive 状态且在运行时,activity 可能位于 生命周期状态 的任何状态。Activitie 和 Fragment 可以在 ViewModel 无感知的情况下被销毁和重新创建。

向 ViewModel 传递 View(Activity/Fragment) 的引用是一个很大的冒险。假设 ViewModel 请求网络,稍后返回数据。
若此时 View 的引用已经被销毁,或者已经成为一个不可见的 Activity。这将导致内存泄漏,甚至 crash。
在 ViewModel 和 View 中通信的建议方式是观察者模式,使用 LiveData 或者其他类库中的可观察对象。

观察者模式

使用观察者模式,让 View 观察和订阅 ViewModel中的变化。
这有如下好处:

ViewModel 的泄露

LiveData 是这个模式的关键组件,你的 Activity 和 Fragment 都会观察 LiveData 实例。
LiveData 如何与其他组件通信取决于你,要注意内存泄露和边界情况。如下图所示,视图层(Presentation Layer)使用观察者模式,数据层(Data Layer)使用回调。

当用户退出应用时,View 不可见了,所以 ViewModel 不需要再被观察。如果数据仓库 Repository 是单例模式并且和应用同作用域,那么直到应用进程被杀死,数据仓库 Repository 才会被销毁。
如果数据仓库 Repository 持有 ViewModel 的回调的引用,那么 ViewModel 将会发生内存泄露。

理想情况下,只要没有被 View 观察了,ViewModel 就应该被释放。

你可以选择下面几种方式来达成目的:

仓库中的 LiveData

为了避免 ViewModel 泄露和回调地狱,数据仓库应该被这样观察:

当 ViewModel 被清除,或者 View 的生命周期结束,订阅也会被清除:

小结

1、不要让 ViewModel 和 Presenter 接触到 Android 框架中的类
2、让 Activity/Fragment 中的逻辑尽量精简
3、避免在 ViewModel 中持有 View 的引用
4、让 UI 观察数据的变化,而不是把数据推送给 UI
5、不要在 ViewModel 中进行保存状态或者数据相关的核心逻辑。 ViewModel 中的每一次调用都可能是最后一次操作。

参考

https://www.jianshu.com/p/7623a9f032ba
https://juejin.cn/post/6844903983471935495
https://juejin.cn/post/6844903975133642759

https://www.mdeditor.tw/pl/2QxK
https://www.jianshu.com/p/e8955f525f4c

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注