LeakCanary如何监听Fragment、Fragment View、ViewModel销毁时机?

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情

本篇文章主要是分析下LeakCanary如何监听Fragment、Fragment View、ViewModel销毁时机的,至于老话常谈的Activity销毁监听大家都知道,就不在此过于阐述了。

添加依赖,基于最新版本分析

dependencies {
    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
}

前置知识

  1. LeakCanary是借助ContentProvider来实现自动初始化的:

image.png

我们可以通过显示在xml中设置leak_canary_watcher_auto_installfalse来关闭其自动初始化。

  1. ContentProvideronCreate()方法会调用AppWatcher.manualInstall(),看下这个方法:

image.png

我们要关注的就是watchersToInstall这个参数,这个参数默认使用appDefaultWatchers()方法进行赋值,走进去看下:

image.png

这个里面就返回了监听Activity、Service、Root View、Fragment、ViewModel要用到的监听对象,看到类名就能知晓它是用来监听什么对象销毁的,接下来我们来一个个的进行分析(除了ActivityWatcher)。

监听Fragment销毁时机

这个使用到的就是FragmentAndViewModelWatcher这个对象实现的,看下里面源码:

image.png

  1. 如果当前SDK版本是8.0及以上就添加AndroidOFragmentDestroyWatcher监听Fragment销毁时机;
  2. 如果当前是Androidx版本的Fragment,就添加AndroidXFragmentDestroyWatcher监听销毁;
  3. 如果是supoort下的Fragment,就添加AndroidSupportFragmentDestroyWatcher监听销毁;

PS:这个地方使用了一个小技巧,如何分别兼容androidxsupport下的Fragment监听:

分别尝试去反射androidx下的androidx.fragment.app.Fragmentsupport下的android.support.v4.app.Fragment,反射失败了就代表不存在当前的包名路径,就不会添加对应的监听,反之就添加对应监听。

这个地方我们就看下AndroidXFragmentDestroyWatcher如何监听销毁Fragment的:

image.png 创建了一个FragmentManager.FragmentLifecycleCallbacks的子类,这个里面就有我们非常熟悉的监听Fragment生命周期的方法。

我们要监听的是Fragment的销毁时机,那就直接重写onFragmentDestroyed方法,将该Fragment对象添加泄漏观察:

image.png

除此之外,我们还发现重写了onFragmentViewDestroyed方法,这就说明还可以监听FragmentView是否发生了内存泄漏。毕竟,FragmentView生命周期和Fragment生命周期不一定是同步的。

image.png

最终我们将这个自定义的FragmentManager.FragmentLifecycleCallbacks的子类对象添加到ActivityFragmentManager中从而实现监听:

image.png

监听ViewModel销毁时机

实现ViewModel监听的类也是FragmentAndViewModelWatcherActivityFragment中的ViewModel销毁监听都能监听得到:

  1. 监听FragmentViewModel销毁的监听类的注入时机就是发生在上面一节自定义FragmentManager.FragmentLifecycleCallbacksonFragmentCreated方法中:

image.png

  1. 监听ActivityViewModel销毁的监听类的注入时机是在调用registerFragmentLifecycleCallbacks注入Fragment生命周期监听的同一处:

image.png

可以发现最终都会调用ViewModelClearedWatcher类实现监听,只不过ActivityFragment各自传入的ViewModelStore不同。

PS:ViewModelStore里面有一个HashMap<String, ViewModel>类型的map对象保存ViewModel

看下ViewModelClearedWatcher这个类:

image.png

它继承了ViewModel这个类,并且将该类注入到了ActivityFragment对应的ViewModelStore中:

image.png

PS: 由于需要创建带构造参数的ViewModel,所以需要自定义一个Factory实现构造参数的注入

然后重写了onClear()方法:

image.png

在该方法中,反射获取ViewModelStore中的mMap集合中保存的所有ViewModel,而onClear()方法只有在ActivityFragment非因配置的更改发生的销毁中被执行,所以当onClear()执行时,就代表ActivityFragment要销毁了,自然能里面的所有ViewModel应该要被销毁了,依次添加到内存泄漏的监听中。

到了这里大家应该明白了,LeakCannary通过向ActivityFragmentViewModelStore注入一个自定义的ViewModel并监听其onClear()的执行时机,从而实现监听ActivityFragment中所有ViewModel的销毁时机,并添加到内存泄漏监听中。

最后

还会有一篇文章来分析LeakCanary如何实现Root ViewService销毁时机的,下篇文章再见!!

猜你喜欢

转载自juejin.im/post/7114311163776598053