从LeakCanary看ViewModel生命周期监控

前面两篇文章中已经了解了LeakCanary中Service和Fragment生命周期监控的实现,那么ViewModel生命周期监控又是怎么实现的呢?

同样的,要了解ViewModel生命周期监控,我们首先应该清楚在代码结构中ViewModel是如何存储获取的,什么时候会销毁ViewModel对象,这也是面试中比较常见的问题。

ViewModel的分类

在Android官方文档中搜索ViewModel,可以看到下图:

从LeakCanary看ViewModel生命周期监控_第1张图片

Google官方先是推出android.arch.lifecycle:viewmodel,随后正式引入AndroidX版本,由于android.arch.lifecycle实现比较久远,这里我们重点讨论androidx中的ViewModel生命周期监控。

ViewModel原理简介

在ViewModel机制中,主要包含ViewModelStore,ViewModelStoreOwner和ViewModelProvider这两个角色,其中ViewModelStoreOwner接口由持有ViewModelStore的类实现,ViewModelStore主要用于存储ViewModel对象,ViewModelProvider是一个工具类,用于构造ViewModel对象,同时在构造时会将构造的对象添加到ViewModelStore中。

ViewModel中的类持有关系

从LeakCanary看ViewModel生命周期监控_第2张图片

如上图所示,开发者通过ViewModelProvider获取ViewModel实例对象,该对象通过Factory构造,构造完成后添加到ViewModelStore中,ViewModelStore被ViewModelStoreOwner持有。

AndroidX中的ViewModel实现

从LeakCanary看ViewModel生命周期监控_第3张图片

如上图所示,为androidx中ViewModel相关的实现,图示比较清楚,配合代码观看即可,不做赘述。

ViewModel的销毁

前面看到ViewModel是存储在ViewModelStore中,那么其销毁自然是在ViewModelStore中处理,ViewModelStore代码如下:

从LeakCanary看ViewModel生命周期监控_第4张图片

可以看到clear方法就是用来清理ViewModelStore中存储的ViewModel对象的,在Activity onDestroy是会调用ViewModelStore的clear方法。

ViewModel销毁监控

从ViewModelStore clear方法的实现可以看出,其首先会遍历mMap中的ViewModel对象,调用每一个的clear方法,随后清空整个mMap,这也就意味着,我们可以通过向该ViewModelStore添加一个ViewModel来达到监控ViewModel销毁的目的,当ViewModel需要被销毁时,我们添加的ViewModel对象的clear方法会被调用,此时mMap还没有清空,我们可以通过遍历mMap来得到所有应该被清空的ViewModel对象信息。

向ViewModelStore添加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方法了,日志如下:

image-20230813000016582

获取所有即将销毁的ViewModel信息

前面已了解过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;
        }

    }
}

运行结果如下:

image-20230813001757434

至此我们就完成了androidx包中Activity关联的ViewModel销毁的监听,至于androidx包下Fragment关联的ViewModel的监听以及arch包下ViewModel的监听,思路是一样的,大家可以探索尝试下,在此不做赘述。

你可能感兴趣的:(leakcanary,android,android,jetpack)