面試系列“講一下吧”之 LeakCanary

如何使用

第一步:添加依賴

debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.2'

第二步:沒了

那他是如何與你的應用程序綁定的

他配置了一個ContentProvider,在 AndroidManifest.xml 中配置, 在 App 打包的時候就會把所有的 AndroidManifest.xml 文件合併到一起。
所以,這個 ContentProvider 就被初始化了。

AndroidManifes.xml 的路徑爲 :leakcanary-object-watcher-android/src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.squareup.leakcanary.objectwatcher"
    >

  <application>
    <provider
        android:name="leakcanary.internal.AppWatcherInstaller$MainProcess"
        android:authorities="${applicationId}.leakcanary-installer"
        android:exported="false"/>
  </application>
</manifest>

我們找到這個類,發現是一個封閉類

internal sealed class AppWatcherInstaller : ContentProvider() {

//找到 onCreate 方法
  override fun onCreate(): Boolean {
    val application = context!!.applicationContext as Application
    //主要看這行
    InternalAppWatcher.install(application)
    return true
  }
}

// -> InternalAppWatcher.kt

fun install(application: Application) {
  SharkLog.logger = DefaultCanaryLog()
  SharkLog.d { "Installing AppWatcher" }
  checkMainThread()
  if (this::application.isInitialized) {
    return
  }
  InternalAppWatcher.application = application
//上面是一些判斷邏輯,主要看下面幾行
  val configProvider = { AppWatcher.config }
  //檢測Activity
  ActivityDestroyWatcher.install(application, objectWatcher, configProvider)
  //檢測Fragment
  FragmentDestroyWatcher.install(application, objectWatcher, configProvider)
  onAppWatcherInstalled(application)
}

//我們來分析Activity的  -> ActivityDestroyWatcher.kt

companion object {
  fun install(
    application: Application,
    objectWatcher: ObjectWatcher,
    configProvider: () -> Config
  ) {
    val activityDestroyWatcher =
      ActivityDestroyWatcher(objectWatcher, configProvider)
      //註冊對activity生命週期的監聽
    application.registerActivityLifecycleCallbacks(activityDestroyWatcher.lifecycleCallbacks)
  }
}

private val lifecycleCallbacks =
//利用委託,不實現其他的生命週期方法,只關注其 Destroy 方法
  object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
    override fun onActivityDestroyed(activity: Activity) {
      if (configProvider().watchActivities) {
      //跟進這個方法繼續看
        objectWatcher.watch(
            activity, "${activity::class.java.name} received Activity#onDestroy() callback"
        )
      }
    }
  }


**
 * Watches the provided [watchedObject].
 *
 * @param description Describes why the object is watched.
 */
@Synchronized fun watch(
  watchedObject: Any,
  description: String
) {
  if (!isEnabled()) {
    return
  }
  //注意觀察這個方法
  removeWeaklyReachableObjects()
  val key = UUID.randomUUID()
      .toString()
  val watchUptimeMillis = clock.uptimeMillis()
  val reference =
    KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
  SharkLog.d {
    "Watching " +
        (if (watchedObject is Class<*>) watchedObject.toString() else "instance of ${watchedObject.javaClass.name}") +
        (if (description.isNotEmpty()) " ($description)" else "") +
        " with key $key"
  }
    
//把當前這個 reference 加到 map 裏面
  watchedObjects[key] = reference
  checkRetainedExecutor.execute {
  //繼續看這個方法
    moveToRetained(key)
  }
}

//這個方法叫  移除弱引用可達的對象,tmd我也不知道啥意思
//說人話: 就是從這個queue中取這個 ref ,如果能取到,說明這個 ref 將要被 GC,這個時候就沒有發生泄漏,我們就可以在 watchedObjects 中刪除掉這個 key。
private fun removeWeaklyReachableObjects() {
  // WeakReferences are enqueued as soon as the object to which they point to becomes weakly
  // reachable. This is before finalization or garbage collection has actually happened.
  var ref: KeyedWeakReference?
  do {
  //注意這個 queue ->  private val queue = ReferenceQueue<Any>() 
    ref = queue.poll() as KeyedWeakReference?
    if (ref != null) {
    //如果能取到,就在這個 map 中移除掉這個key   ->  private val watchedObjects = mutableMapOf<String, KeyedWeakReference>()
    // value 其實就是引用的 activity
      watchedObjects.remove(ref.key)
    }
  } while (ref != null)
}


@Synchronized private fun moveToRetained(key: String) {
//如果已經在queue中能取到,說明可以進行GC了,就在 watchedObjects 中移除,我們就不需要再觀察了。
  removeWeaklyReachableObjects()
  val retainedRef = watchedObjects[key]
  if (retainedRef != null) {
  //這個時候,如果發現 ref 沒有被刪除,這就說明發生了泄漏
    retainedRef.retainedUptimeMillis = clock.uptimeMillis()
    onObjectRetainedListeners.forEach { it.onObjectRetained() }
  }
}




困了,就先這樣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章