1、无代码集成原理
目前最新版本是2.8.1,看文档从2.0版本集成时就不需要修改任何代码了,只需要在build.gradle里面添加一行引用:
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.xxxx'
debugImplementation保证了只在debug环境引入,关于初始化,我们在源码中看到在AndroidManifest.xml中配置了一个provider:
<provider
android:name="leakcanary.internal.MainProcessAppWatcherInstaller"
android:authorities="${applicationId}.leakcanary-installer"
android:enabled="@bool/leak_canary_watcher_auto_install"
android:exported="false"/>
而在provider中我们可以看到初始化代码:
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
AppWatcher.manualInstall(application)
return true
}
通过相关资料可以知道,provider会在application的onCreate调用之前初始化,所以在provider中对leakcanary初始化,跟手动在application中初始化基本一致。
2、内存泄露监控原理
默认只监控Activity、Fragment、RootView、Service类型的泄露,而这些类型对象有类似与声明周期的节点,知道对象需要释放了。在这个节点,例如Activity的onDestroy(),在这个声明周期后,这个对象就需要释放了,此时对此对象进行监控,看5秒后有没有释放,如果没有释放的话,会触发GC后再判断,如果还没有释放,会认为此对象存在内存泄露,leakcanary会手机泄露信息展示出来。
关于怎么监控一个对象有没有释放,是利用了WeakReference的一个特性,就是创建弱引用时指定一个引用队列(ReferenceQueue),当引用的对象被回收,虚拟机会把此弱引用加入到关联的引用队列中。通过ReferenceQueue中的内容,可以判断对象是否被回收。
3、不同对象监控实现
Activity的监控是通过注册声明周期回调,监听activity销毁时,开始对activity开始监控
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityDestroyed(activity: Activity) {
reachabilityWatcher.expectWeaklyReachable(
activity, "${activity::class.java.name} received Activity#onDestroy() callback"
)
}
}
override fun install() {
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
Fragment的监控同样是通过注册声明周期回调:
override fun invoke(activity: Activity) {
val fragmentManager = activity.fragmentManager
fragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
}
override fun onFragmentDestroyed( fm: FragmentManager, fragment: Fragment) {
reachabilityWatcher.expectWeaklyReachable(
fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback")
}
View是监控onViewDetachedFromWindow()调用:
rootView.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {
val watchDetachedView = Runnable {
reachabilityWatcher.expectWeaklyReachable(
rootView, "${rootView::class.java.name} received View#onDetachedFromWindow() callback"
)
}
override fun onViewDetachedFromWindow(v: View) {
mainHandler.post(watchDetachedView)
}
})