LeakCanary(1)初始化源码中的面试题

344 阅读1分钟

如何使用

官网的教程是直接在依赖里配置这一行就可以了。

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。