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