@TryLoveCatch
2021-04-08T12:07:51.000000Z
字数 19080
阅读 1632
android Jetpack ViewModel
ViewModelProviders
https://toutiao.io/posts/hd57u6/preview
public class AViewModel extends ViewModel {private MutableLiveData<User> userLiveData = new MutableLiveData<User>();public LiveData getUser(){//获取数据loadData();return userLiveData;}private void loadData(){new Thread(){@Overridepublic void run() {// postValue: 接收端在主线程回调数据。// setValue: 接收端数据回调与发送端同一个线程。userLiveData.postValue(new User());}}.start();}public LiveData getDatas(){return userLiveData;}public void updateUser(){loadData();}}
ViewModel里面不要有Andrid库相关的类,例如context等
public class ActivityA extends AppCompatActivity {//...ViewModelProviders.of(ActivityA.this).get(AViewModel.class).getUser().observe(this, new Observer<User>() {@Overridepublic void onChanged(@Nullable User user) {//获取数据变化}});}
需要传入Activity
ViewModel只会在Activity存活时,只会创建一次,因此
在同一个Activity中可以在多个Fragment中共享ViewModel中数据。
public class FragmentA extends Fragment{//...ViewModelProviders.of(getActivity()).get(AViewModel.class).getDatas().observe(this, new Observer<User>() {@Overridepublic void onChanged(@Nullable User user) {//获取Activity中数据变化}});}
public class FragmentB extends Fragment{//...ViewModelProviders.of(getActivity()).get(AViewModel.class).getDatas().observe(this, new Observer<User>() {@Overridepublic void onChanged(@Nullable User user) {//获取Activity中数据变化}});}
public class AndroidViewModel extends ViewModel {@SuppressLint("StaticFieldLeak")private Application mApplication;public AndroidViewModel(@NonNull Application application) {mApplication = application;}/*** Return the application.*/@SuppressWarnings("TypeParameterUnusedInFormals")@NonNullpublic <T extends Application> T getApplication() {//noinspection uncheckedreturn (T) mApplication;}}
提供了Application
基于android.arch.lifecycle的1.1.1版本
下图说明了Activity经历屏幕旋转直到最终destroyed掉这整个过程中所经历的各个生命周期。该图还在关联的Activity生命周期的旁边显示了ViewModel的生命周期。

我们可以看出,ViewModel的生命周期贯穿Activity始终,直到Activity正常结束,并不会因为屏幕旋转等系统原因而导致ViewModel生命周期提前结束。同理Fragment对于ViewModel也一样。
我们从使用的入口函数一步一步来看:
ViewModelProviders.of(getActivity()).get(AViewModel.class)
@NonNull@MainThreadpublic static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {Application application = checkApplication(checkActivity(fragment));if (factory == null) {factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);}return new ViewModelProvider(ViewModelStores.of(fragment), factory);}@NonNull@MainThreadpublic 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);}
先去得到Application,因为我们调用的时候of()的是一个参数方法,所以factory肯定为null,关于factory后面在说,我们继续看。
这里需要注意的是,既然factory可以由外部来传入,所以我们可以不使用系统的反射factory,可以来定制自己的factory,只需要实现create方法就行了
在new ViewModelProvider的时候,先调用ViewModelStores.of(),我们看下源码:
public class ViewModelStores {private ViewModelStores() {}/*** Returns the {@link ViewModelStore} of the given activity.** @param activity an activity whose {@code ViewModelStore} is requested* @return a {@code ViewModelStore}*/@NonNull@MainThreadpublic static ViewModelStore of(@NonNull FragmentActivity activity) {if (activity instanceof ViewModelStoreOwner) {return ((ViewModelStoreOwner) activity).getViewModelStore();}return holderFragmentFor(activity).getViewModelStore();}/*** Returns the {@link ViewModelStore} of the given fragment.** @param fragment a fragment whose {@code ViewModelStore} is requested* @return a {@code ViewModelStore}*/@NonNull@MainThreadpublic static ViewModelStore of(@NonNull Fragment fragment) {if (fragment instanceof ViewModelStoreOwner) {return ((ViewModelStoreOwner) fragment).getViewModelStore();}return holderFragmentFor(fragment).getViewModelStore();}}
ViewModelStores代码很简单,类似于ViewModelProviders,看代码可知,就是从Activity或者Fragment里面获取ViewModelStore,然后传给ViewModelProvider。
一般来说,我们都是走了holderFragmentFor(),会返回一个HolderFragment,我们的ViewModelStore是通过HolderFragment#getViewModelStore()来获取的,在后面我们会单独来说下这个HolderFragment
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);}
得到ViewModelProvider之后,就会调用它的get()方法:
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {String canonicalName = modelClass.getCanonicalName();if (canonicalName == null) {throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");}return get(DEFAULT_KEY + ":" + canonicalName, modelClass);}public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {ViewModel viewModel = mViewModelStore.get(key);if (modelClass.isInstance(viewModel)) {//noinspection uncheckedreturn (T) viewModel;} else {//noinspection StatementWithEmptyBodyif (viewModel != null) {// TODO: log a warning.}}viewModel = mFactory.create(modelClass);mViewModelStore.put(key, viewModel);//noinspection uncheckedreturn (T) viewModel;}
先来看key,得到了传入ViewModel的canonicalName:
getName com.test.TestClassgetCanonicalName com.test.TestClassgetSimpleName TestClassgetName com.test.TestClass$TestInnerClassgetCanonicalName com.test.TestClass.TestInnerClassgetSimpleName TestInnerClassgetName [Lcom.test.TestClass$TestInnerClass;getCanonicalName com.test.TestClass.TestInnerClass[]getSimpleName TestInnerClass[]
然后根据这个key,从ViewModelStore里面去获取ViewModel:
ViewModel viewModel = mViewModelStore.get(key);
我们来看一下ViewModelStore的代码:
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);}/*** Clears internal storage and notifies ViewModels that they are no longer used.*/public final void clear() {for (ViewModel vm : mMap.values()) {vm.onCleared();}mMap.clear();}}
ViewModelStore里面只有一个Map,就是一个ViewModel和className对应的缓存
然后,如果我们得到的这个ViewModel,就是传入modelClass的实例的话,就直接返回,否则,呃,并没有实现,只有一个空的if。。
public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {private static AndroidViewModelFactory sInstance;/*** Retrieve a singleton instance of AndroidViewModelFactory.** @param application an application to pass in {@link AndroidViewModel}* @return A valid {@link AndroidViewModelFactory}*/@NonNullpublic static AndroidViewModelFactory getInstance(@NonNull Application application) {if (sInstance == null) {sInstance = new AndroidViewModelFactory(application);}return sInstance;}private Application mApplication;/*** Creates a {@code AndroidViewModelFactory}** @param application an application to pass in {@link AndroidViewModel}*/public AndroidViewModelFactory(@NonNull Application application) {mApplication = application;}@NonNull@Overridepublic <T extends ViewModel> T create(@NonNull Class<T> modelClass) {if (AndroidViewModel.class.isAssignableFrom(modelClass)) {//noinspection TryWithIdenticalCatchestry {return modelClass.getConstructor(Application.class).newInstance(mApplication);} catch (NoSuchMethodException e) {throw new RuntimeException("Cannot create an instance of " + modelClass, e);} catch (IllegalAccessException e) {throw new RuntimeException("Cannot create an instance of " + modelClass, e);} catch (InstantiationException e) {throw new RuntimeException("Cannot create an instance of " + modelClass, e);} catch (InvocationTargetException e) {throw new RuntimeException("Cannot create an instance of " + modelClass, e);}}return super.create(modelClass);}}
可以看出来AndroidViewModelFactory是一个单例,构造函数的参数也是Application,所以可以确定factory是唯一的。
我们创建的是AndroidViewModelFactory,继承自NewInstanceFactory,NewInstanceFactory里面是直接默认构造函数创建ViewModel,而AndroidViewModelFactory会使用一个参数Application的构造函数来创建AndroidViewModel。
很简单,因为用到来反射,所以会增加keep:
-keep class android.arch.lifecycle.** { *; }-keep class android.arch.core.internal.SafeIterableMap { *; }
https://www.mdeditor.tw/pl/2QxK
HolderFragment是保证ViewModel在屏幕旋转等系统销毁之后,保持唯一的核心方法。
ViewModel 对生命周期的管理与 Glide 和 RxPermission 等框架的处理方式一致,就是使用一个空的 Fragment 来进行生命周期管理。
利用无View的HolderFragment,使用setRetainInstance(true)保证其在config change时不被销毁
public class HolderFragment extends Fragment implements ViewModelStoreOwner {private static final String LOG_TAG = "ViewModelStores";// 这是什么?请看下面注释分析private static final HolderFragmentManager sHolderFragmentManager = new HolderFragmentManager();@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)public static final String HOLDER_TAG = "android.arch.lifecycle.state.StateProviderHolderFragment";// 这就是我们存放 ViewModel 的 ViewModelStore,就定义在 HolderFragment里private ViewModelStore mViewModelStore = new ViewModelStore();public HolderFragment() {// 划重点啦!!!为什么当 activity 由于屏幕旋转等被系统销毁时,// 这个 fragment 实例也不会被销毁?因为设置了 setRetainInstance(true)setRetainInstance(true);}@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 当 Fragment 的 onCreate 方法执行,说明了 Fragment 已经成功添加到了 Activity,// sHolderFragmentManager 是 HolderFragmentManager类,它的 holderFragmentCreated()方法// 是将该 Fragment 从 mNotCommittedActivityHolders 或 mNotCommittedFragmentHolders 中移除// (HolderFragmentManager 的说明,请看下面的注释)sHolderFragmentManager.holderFragmentCreated(this);}@Overridepublic void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);}@Overridepublic void onDestroy() {super.onDestroy();// 当一个设置了 setRetainInstance(true) 的 Fragment 的 onDestroy 方法被调用,// 证明它依附的 Activity 已经寿终正寝,所以调用 mViewModelStore.clear(),// 前面我们已经说了,这个 clear 方法会调用所有 ViewModel 对象的 onCleared 方法// 并且清空它们,我们可以在 ViewModel 的onCleared 方法做一些处理,以免起来不必要的// 内存泄漏等问题mViewModelStore.clear();}// 该方法用于给外部调用,返回 ViewModelStore@Overridepublic ViewModelStore getViewModelStore() {return mViewModelStore;}// 静态方法,没 ViewModelStores.of 方法中被调用// 作用:在 activity 中添加一个 HolderFragment 用于存储存放了ViewModel对象的ViewModelStorepublic static HolderFragment holderFragmentFor(FragmentActivity activity) {return sHolderFragmentManager.holderFragmentFor(activity);}// 静态方法,没 ViewModelStores.of 方法中被调用// 作用:在 fragment 中添加一个 HolderFragment 用于存储存放了ViewModel对象的ViewModelStore@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)public static HolderFragment holderFragmentFor(Fragment fragment) {return sHolderFragmentManager.holderFragmentFor(fragment);}// 上面的大部分操作都是基于HolderFragmentManager,我们来分析下这个类@SuppressWarnings("WeakerAccess")static class HolderFragmentManager {// 存放还没被系统正式添加到 Activity 中的 HolderFragmentprivate Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>();private Map<Fragment, HolderFragment> mNotCommittedFragmentHolders = new HashMap<>();// 声明定义了一个能够感知 Activity 生命周期的 ActivityLifecycleCallbacksprivate ActivityLifecycleCallbacks mActivityCallbacks =new EmptyActivityLifecycleCallbacks() {@Overridepublic void onActivityDestroyed(Activity activity) {// 当 Activity destroy 的时候,清除 mNotCommittedActivityHolders 中保存// 的对应 HolderFragment。前面我们分析了 HolderFragment 的 onCreate 方法中// 会请一次 mNotCommittedActivityHolders,为什么在这么还要多此一举呢?其实// 并不是多此一举,因为 Fragment 有可能还没创建完,Activity 就夭折了,那这样子// HodlerFragment 的 onCreate 就无法调用,所以在加多一层清理机制,确保能够// 清除掉(不得不感叹,谷歌官方的严谨以及对源码的掌控理解能力)HolderFragment fragment = mNotCommittedActivityHolders.remove(activity);if (fragment != null) {Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity);}}};private boolean mActivityCallbacksIsAdded = false;private FragmentLifecycleCallbacks mParentDestroyedCallback =new FragmentLifecycleCallbacks() {@Overridepublic void onFragmentDestroyed(FragmentManager fm, Fragment parentFragment) {// 与 mActivityCallbacks 的分析同理super.onFragmentDestroyed(fm, parentFragment);HolderFragment fragment = mNotCommittedFragmentHolders.remove(parentFragment);if (fragment != null) {Log.e(LOG_TAG, "Failed to save a ViewModel for " + parentFragment);}}};// HolderFragment 的 onCreate 生命周期被回调,就会调用这个方法,清除// mNotCommittedActivityHolders 或者 mNotCommittedFragmentHolders 中// 的引用的 HolderFragmentvoid holderFragmentCreated(Fragment holderFragment) {Fragment parentFragment = holderFragment.getParentFragment();if (parentFragment != null) {mNotCommittedFragmentHolders.remove(parentFragment);parentFragment.getFragmentManager().unregisterFragmentLifecycleCallbacks(mParentDestroyedCallback);} else {mNotCommittedActivityHolders.remove(holderFragment.getActivity());}}private static HolderFragment findHolderFragment(FragmentManager manager) {if (manager.isDestroyed()) {throw new IllegalStateException("Can't access ViewModels from onDestroy");}Fragment fragmentByTag = manager.findFragmentByTag(HOLDER_TAG);if (fragmentByTag != null && !(fragmentByTag instanceof HolderFragment)) {throw new IllegalStateException("Unexpected "+ "fragment instance was returned by HOLDER_TAG");}return (HolderFragment) fragmentByTag;}private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {HolderFragment holder = new HolderFragment();fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();return 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);// 我们新添加 add 的 Fragment 并不会马上就执行添加完(也就是说,这个方法执行完成后,马上再// 调用一次,上面的 findHolderFragment 会返回 null。但是这没有关系,因为接下来我们还可// 从 mNotCommittedActivityHolders 获取到对应的实例),所以我们这里先把他放在// mNotCommittedActivityHolders 中。Not Committed 表示 fragment 的 commit 还没有完成mNotCommittedActivityHolders.put(activity, holder);return holder;}HolderFragment holderFragmentFor(Fragment parentFragment) {FragmentManager fm = parentFragment.getChildFragmentManager();HolderFragment holder = findHolderFragment(fm);if (holder != null) {return holder;}holder = mNotCommittedFragmentHolders.get(parentFragment);if (holder != null) {return holder;}parentFragment.getFragmentManager().registerFragmentLifecycleCallbacks(mParentDestroyedCallback, false);holder = createHolderFragment(fm);// 同上mNotCommittedFragmentHolders.put(parentFragment, holder);return holder;}}}
https://blog.csdn.net/Gaugamela/article/details/56280384
Fragment具有属性retainInstance,默认值为false。
- false: 当设备旋转时,fragment会随托管activity一起销毁并重建。
- true: 当设备旋转时,fragment不会随着activity一起被销毁,它会一直保留(进程不消亡的前提下),并在需要时原封不动地传递给新的Activity。
示例代码如下:
@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setRetainInstance(true);...........}
虽然保留的fragment没有被销毁,但它已脱离消亡中的activity并处于保留状态。
尽管此时的fragment仍然存在,但已经没有任何activity托管它,其生命周期如下图所示:

HolderFragment掌控了ViewModel的生命周期。
ViewModelProvider每次都是new的,里面只持有了ViewModelStore,而我们的ViewModel是存在ViewModelStore中的,所以我们需要关心ViewModelStore是什么时候释放的?
public class ViewModelStore {private final HashMap<String, ViewModel> mMap = new HashMap<>();/*** Clears internal storage and notifies ViewModels that they are no longer used.*/public final void clear() {for (ViewModel vm : mMap.values()) {vm.onCleared();}mMap.clear();}}
可以看到ViewModelStore里面有一个clear方法:
那么是什么时候调用的呢?
@Overridepublic void onDestroy() {super.onDestroy();mViewModelStore.clear();}
是在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 |

回答几个问题:
GC垃圾回收机制不会回收被强引用的对象。在开发过程中,我们需要存储的数据被ViewModel引用,ViewModel被ViewModelStore引用,而ViewModelStore又被HolderFragment引用,于是就形成了一条引用链:HolderFragment->ViewModelStore->ViewModel->我们想要存储的数据(最佳实践是LiveData)。通过上面HolderFragment的分析,我们知道HodlerFragment在创建时,设置了setRetainInstance(true),因此它使得自身能够不受到屏幕旋转等configuration changes影响而存活,直到依附的Activity正常结束。
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中的变化。
这有如下好处:
LiveData 是这个模式的关键组件,你的 Activity 和 Fragment 都会观察 LiveData 实例。
LiveData 如何与其他组件通信取决于你,要注意内存泄露和边界情况。如下图所示,视图层(Presentation Layer)使用观察者模式,数据层(Data Layer)使用回调。

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

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

你可以选择下面几种方式来达成目的:
为了避免 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