如何使用
官网的教程是直接在依赖里配置这一行就可以了。
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.10'
神奇吧。那是如何启动的呢。
如何启动
按照第三方开源框架获取 context 的经验来讲,大概率是 Provider,于是我们就直奔源码,去寻找 provider。 新建了一个demo,只引入leakCanary,筛选其中的provider就得到了答案。
<provider android:name="leakcanary.internal.LeakCanaryFileProvider"
android:exported="false"
android:authorities="com.squareup.leakcanary.fileprovider.com.example.leakcanarydemo"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/leak_canary_file_paths"/>
</provider>
<provider android:name="leakcanary.internal.MainProcessAppWatcherInstaller"
android:enabled="@bool/leak_canary_watcher_auto_install"
android:exported="false"
android:authorities="com.example.leakcanarydemo.leakcanary-installer"/>
<provider android:name="leakcanary.internal.PlumberInstaller"
android:enabled="@bool/leak_canary_plumber_auto_install"
android:exported="false"
android:authorities="com.example.leakcanarydemo.plumber-installer"/>
找到三个Provider,但是凭感觉来看,应该是先看 MainProcessAppWatcherInstaller
MainProcessAppWatcherInstaller
internal class MainProcessAppWatcherInstaller : ContentProvider() {
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
//关键行
AppWatcher.manualInstall(application)
return true
}
}
插入一个面试题: 面试题:ContentProvider 的启动和 Application 的启动哪个早? 答案是: Content providers are loaded before the application class is created 在这个类的注释里写的清清楚楚。
AppWatch#manualInstall
关键代码1 loadLeakCanary
LeakCanaryDelegate.loadLeakCanary(application)
internal object LeakCanaryDelegate {
@Suppress("UNCHECKED_CAST")
val loadLeakCanary by lazy {
try {
val leakCanaryListener = Class.forName("leakcanary.internal.InternalLeakCanary")
leakCanaryListener.getDeclaredField("INSTANCE")
.get(null) as (Application) -> Unit
} catch (ignored: Throwable) {
NoLeakCanary
}
}
}
这里就涉及到了反射的知识。可以问的面试题有。
面试题:getDeclaredField是什么意思?
面试题:为什么传入 INSTANCE ?
面试题:Field.get(null)是什么意思,什么情况下可以传null。
If the underlying field is a static field, the obj argument is ignored; it may be null.
面试题:这个地方为什么需要用反射?
这行代码所在的库是 leakcanary-object-watcher-android-core
InternalLeakCanary所在的库是 leakcanary-android-core
关键代码2
watchersToInstall.forEach {
it.install()
}
补充下刚才的参数
fun appDefaultWatchers(
application: Application,
reachabilityWatcher: ReachabilityWatcher = objectWatcher
): List<InstallableWatcher> {
return listOf(
ActivityWatcher(application, reachabilityWatcher),
FragmentAndViewModelWatcher(application, reachabilityWatcher),
RootViewWatcher(reachabilityWatcher),
ServiceWatcher(reachabilityWatcher)
)
}
可以引出面试题:LeakCanary可以监控哪些场景的内存泄漏。
日拱一卒,今天先到这里。BYE。