前面两篇文章中已经了解了LeakCanary中Service和Fragment生命周期监控的实现,那么ViewModel生命周期监控又是怎么实现的呢?
同样的,要了解ViewModel生命周期监控,我们首先应该清楚在代码结构中ViewModel是如何存储获取的,什么时候会销毁ViewModel对象,这也是面试中比较常见的问题。
在Android官方文档中搜索ViewModel,可以看到下图:
Google官方先是推出android.arch.lifecycle:viewmodel,随后正式引入AndroidX版本,由于android.arch.lifecycle实现比较久远,这里我们重点讨论androidx中的ViewModel生命周期监控。
在ViewModel机制中,主要包含ViewModelStore,ViewModelStoreOwner和ViewModelProvider这两个角色,其中ViewModelStoreOwner接口由持有ViewModelStore的类实现,ViewModelStore主要用于存储ViewModel对象,ViewModelProvider是一个工具类,用于构造ViewModel对象,同时在构造时会将构造的对象添加到ViewModelStore中。
如上图所示,开发者通过ViewModelProvider获取ViewModel实例对象,该对象通过Factory构造,构造完成后添加到ViewModelStore中,ViewModelStore被ViewModelStoreOwner持有。
如上图所示,为androidx中ViewModel相关的实现,图示比较清楚,配合代码观看即可,不做赘述。
前面看到ViewModel是存储在ViewModelStore中,那么其销毁自然是在ViewModelStore中处理,ViewModelStore代码如下:
可以看到clear方法就是用来清理ViewModelStore中存储的ViewModel对象的,在Activity onDestroy是会调用ViewModelStore的clear方法。
从ViewModelStore clear方法的实现可以看出,其首先会遍历mMap中的ViewModel对象,调用每一个的clear方法,随后清空整个mMap,这也就意味着,我们可以通过向该ViewModelStore添加一个ViewModel来达到监控ViewModel销毁的目的,当ViewModel需要被销毁时,我们添加的ViewModel对象的clear方法会被调用,此时mMap还没有清空,我们可以通过遍历mMap来得到所有应该被清空的ViewModel对象信息。
向ViewModelStore添加我们自定义的ViewModelClearedWatcher,用于监控ViewModel的销毁,实现代码如下:
public class ViewModelWatcher {
private static final String TAG = "ViewModelWatcher";
private static volatile ViewModelWatcher mInstance;
private ViewModelWatcher() {
}
public static ViewModelWatcher getInstance() {
if (null == mInstance) {
synchronized (ViewModelWatcher.class) {
if (null == mInstance) {
mInstance = new ViewModelWatcher();
}
}
}
return mInstance;
}
public void init(Application application) {
application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
// 如果Activity是androidx中的ComponentActivity,
// 则向该Activity中添加ViewModel
if (activity instanceof ComponentActivity) {
ViewModelProvider viewModelProvider = new ViewModelProvider((ViewModelStoreOwner) activity, new ViewModelProvider.Factory() {
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (modelClass.isAssignableFrom(ViewModelClearedWatcher.class)) {
return (T) (new ViewModelClearedWatcher((ViewModelStoreOwner) activity));
}
return null;
}
});
viewModelProvider.get(ViewModelClearedWatcher.class);
}
}
@Override
public void onActivityStarted(@NonNull Activity activity) {
}
@Override
public void onActivityResumed(@NonNull Activity activity) {
}
@Override
public void onActivityPaused(@NonNull Activity activity) {
}
@Override
public void onActivityStopped(@NonNull Activity activity) {
}
@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
}
@Override
public void onActivityDestroyed(@NonNull Activity activity) {
}
});
}
class ViewModelClearedWatcher extends ViewModel {
private ViewModelStoreOwner mViewModelStoreOwner;
public ViewModelClearedWatcher(ViewModelStoreOwner viewModelStoreOwner) {
this.mViewModelStoreOwner = viewModelStoreOwner;
}
@Override
protected void onCleared() {
Log.d(TAG,"view model has been cleared!");
super.onCleared();
}
}
}
运行可以看到确实监听到clear方法了,日志如下:
前面已了解过ViewModel存储在ViewModelStore的mMap对象中,这也就意味着我们可以通过反射获取Map对象并遍历来获取即将被销毁的所有ViewModel信息,代码如下:
class ViewModelClearedWatcher extends ViewModel {
private ViewModelStoreOwner mViewModelStoreOwner;
public ViewModelClearedWatcher(ViewModelStoreOwner viewModelStoreOwner) {
this.mViewModelStoreOwner = viewModelStoreOwner;
}
@Override
protected void onCleared() {
Log.d(TAG, "view model has been cleared!");
Map<String, ViewModel> map = getMapFromViewModelStore();
if (map != null && !map.isEmpty()) {
for (ViewModel viewModel : map.values()) {
Log.d(TAG, "viewModel been cleared:" + viewModel.toString());
}
}
super.onCleared();
}
private Map<String, ViewModel> getMapFromViewModelStore() {
try {
Class<?> viewModelStoreClass =
Class.forName(ViewModelStore.class.getName());
Field field = viewModelStoreClass.getDeclaredField("mMap");
field.setAccessible(true);
return (Map<String, ViewModel>) field.get(mViewModelStoreOwner.getViewModelStore());
} catch (NoSuchFieldException | ClassNotFoundException | IllegalAccessException e) {
e.printStackTrace();
return null;
}
}
}
运行结果如下:
至此我们就完成了androidx包中Activity关联的ViewModel销毁的监听,至于androidx包下Fragment关联的ViewModel的监听以及arch包下ViewModel的监听,思路是一样的,大家可以探索尝试下,在此不做赘述。