LeakCanry的一些奇奇怪怪的操作

/ 0评 / 0

1、动态显示隐藏图标

通过xml配置,如下

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <bool name="leak_canary_add_launcher_icon">false</bool>
</resources>

通过代码动态配置

leakcanary.LeakCanary#showLeakDisplayActivityLauncherIcon

去掉默认Toast

LeakCanary.config = LeakCanary.config.run {
  copy(
    eventListeners = eventListeners.filter {
      it !is ToastEventListener
    }
  )
}

手动dump

//关闭自动dump
LeakCanary.config = LeakCanary.config.copy(
    dumpHeap = false
)

//手动dump
LeakCanary.dumpHeap()

关闭自动启用

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <bool name="leak_canary_watcher_auto_install">false</bool>
</resources>
/主动启用
val watchersToInstall = AppWatcher.appDefaultWatchers(application)
AppWatcher.manualInstall(
  application = application,
  watchersToInstall = watchersToInstall
)

内存泄露自动上报

//添加监听
val eventListener = LeakCanary.config.eventListeners.toMutableList().also {
    it.add(LeakRecordEventListener)
}
LeakCanary.config = LeakCanary.config.copy(
    eventListeners = eventListener
)

监听的实现

object LeakRecordEventListener : EventListener {

    private const val TAG = "LeakRecordEventListener"

    private val appInfo: AppInfo by lazy {
        AppInfo(
            PhoneUtil.getAppVersionName(),
            PhoneUtil.getAppVersionCode(AppContext.application)
        )
    }

    private val devicesInfo: DevicesInfo by lazy {
        DevicesInfo(
            Build.VERSION.SDK_INT,
            Build.BRAND,
            Build.PRODUCT
        )
    }

    override fun onEvent(event: EventListener.Event) {
        Log.i(TAG, "onEvent: $event")
        if (event is EventListener.Event.HeapAnalysisDone.HeapAnalysisSucceeded) {
            record(event)
        }
    }

    private fun record(heapAnalysis: EventListener.Event.HeapAnalysisDone.HeapAnalysisSucceeded) {
        val leakInfos = mutableListOf<LeakInfo>()
        heapAnalysis.heapAnalysis.allLeaks.forEach { leakInfo ->
            val signature = leakInfo.signature
            val leakingObject = leakInfo.leakTraces.first().leakingObject
            val className = leakingObject.className
            val classSimpleName = leakingObject.classSimpleName

            val fullLeakStack = leakInfo.toString()
            val info = LeakInfo(
                signature,
                className,
                classSimpleName,
                fullLeakStack,
                devicesInfo,
                appInfo,
                channel = BuildConfig.MEMORY_LEAK_CHANNEL
            )
            leakInfos.add(info)
        }
        recordLeakInfo(leakInfos)
    }

    private fun recordLeakInfo(leakInfos: List<LeakInfo>) {
        if (leakInfos.isEmpty()) {
            Log.i(TAG, "recordLeakInfo: size is empty")
            return
        }
        Log.i(TAG, "record: >>>>>>>")
        //上报的代码
    }
}

data class LeakInfo(
    val signature: String,
    val className: String,
    val classSimpleName: String,
    val fullLeakStack: String,
    val devicesInfo: DevicesInfo,
    val appInfo: AppInfo,
    val channel: String = ""
)

data class DevicesInfo(
    val sdkVersion: Int,
    val brand: String,
    val product: String
)

data class AppInfo(
    val versionName: String,
    val versionCode: Int
)

堆栈还原

如果App被混淆了,需要获取混淆前的泄露堆栈,可以把mapping文件放入app assets目录下,文件名固定位leakCanaryObfuscationMapping.txt

详见: leakcanary.internal.AndroidDebugHeapAnalyzer

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注