@TryLoveCatch
2021-04-08T20:07:51.000000Z
字数 19080
阅读 1271
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(){
@Override
public 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>() {
@Override
public 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>() {
@Override
public void onChanged(@Nullable User user) {
//获取Activity中数据变化
}
});
}
public class FragmentB extends Fragment{
//...
ViewModelProviders.of(getActivity()).get(AViewModel.class).getDatas().observe(this, new Observer<User>() {
@Override
public 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")
@NonNull
public <T extends Application> T getApplication() {
//noinspection unchecked
return (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
@MainThread
public 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
@MainThread
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);
}
先去得到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
@MainThread
public 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
@MainThread
public 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 unchecked
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
先来看key,得到了传入ViewModel的canonicalName:
getName com.test.TestClass
getCanonicalName com.test.TestClass
getSimpleName TestClass
getName com.test.TestClass$TestInnerClass
getCanonicalName com.test.TestClass.TestInnerClass
getSimpleName TestInnerClass
getName [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}
*/
@NonNull
public 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
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
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);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 当 Fragment 的 onCreate 方法执行,说明了 Fragment 已经成功添加到了 Activity,
// sHolderFragmentManager 是 HolderFragmentManager类,它的 holderFragmentCreated()方法
// 是将该 Fragment 从 mNotCommittedActivityHolders 或 mNotCommittedFragmentHolders 中移除
// (HolderFragmentManager 的说明,请看下面的注释)
sHolderFragmentManager.holderFragmentCreated(this);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
public void onDestroy() {
super.onDestroy();
// 当一个设置了 setRetainInstance(true) 的 Fragment 的 onDestroy 方法被调用,
// 证明它依附的 Activity 已经寿终正寝,所以调用 mViewModelStore.clear(),
// 前面我们已经说了,这个 clear 方法会调用所有 ViewModel 对象的 onCleared 方法
// 并且清空它们,我们可以在 ViewModel 的onCleared 方法做一些处理,以免起来不必要的
// 内存泄漏等问题
mViewModelStore.clear();
}
// 该方法用于给外部调用,返回 ViewModelStore
@Override
public ViewModelStore getViewModelStore() {
return mViewModelStore;
}
// 静态方法,没 ViewModelStores.of 方法中被调用
// 作用:在 activity 中添加一个 HolderFragment 用于存储存放了ViewModel对象的ViewModelStore
public 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 中的 HolderFragment
private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>();
private Map<Fragment, HolderFragment> mNotCommittedFragmentHolders = new HashMap<>();
// 声明定义了一个能够感知 Activity 生命周期的 ActivityLifecycleCallbacks
private ActivityLifecycleCallbacks mActivityCallbacks =
new EmptyActivityLifecycleCallbacks() {
@Override
public 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() {
@Override
public 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 中
// 的引用的 HolderFragment
void 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。
示例代码如下:
@Override
public 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方法:
那么是什么时候调用的呢?
@Override
public 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