3. Application 初始化配置:自动安装、自定义监听、延迟初始化

3.1 原理概述

LeakCanary 的初始化触发点位于 ContentProvider 的 onCreate 方法中。Android 系统在 Application 的 onCreate 执行前会自动调用所有注册的 ContentProvider,从而“无侵入”地完成 LeakCanary 安装。这种自动安装方式虽然便捷,但在复杂业务场景下可能需要调整:

  • 自动安装:默认行为,无需任何代码,通过 Manifest 中声明的 InternalLeakCanaryProvider 自动注册。
  • 自定义监听:替换或扩展默认的泄漏分析行为,例如自定义堆转储处理、上报到后端。
  • 延迟初始化:将初始化时机推迟到 Application onCreate 结束甚至用户首次交互之后,降低冷启动耗时。

3.2 三种初始化方式的实现流程

方式 触发时机 核心代码/配置 适用场景
自动安装 ContentProvider.onCreate(APP启动早期) 无配置,依赖库默认注册 调试环境,快速接入
自定义监听 ContentProvider.onCreate 后立即执行 实现 OnHeapAnalyzedListener 并通过 LeakCanary.config 注入 需定制堆转储处理或上报
延迟初始化 Application.onCreate 末尾或首次进入主界面 在 Application 类中手动调用 LeakCanary.install(application) 对启动耗时敏感的生产/灰度环境

3.3 核心代码与 API

3.3.1 自动安装(默认)

只需在 build.gradle 中添加依赖,无需任何初始化代码:

dependencies {
    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14'
}

LeakCanary 自动通过 InternalLeakCanaryProvider 完成安装,内部创建 LeakCanary.Config 并调用 LeakCanary.install(application)。

3.3.2 自定义监听

在 Application 的 onCreate 中覆写默认配置:

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        // 仅在 debug 构建中触发,避免 Release 包被误配置
        if (LeakCanary.isInAnalyzerProcess) return

        val customListener = OnHeapAnalyzedListener { heapAnalysis ->
            // 自定义处理:保存到文件、上报服务器等
            heapAnalysis.let {
                Log.d("LeakCanary", "分析结果: ${it.toString().take(200)}")
            }
        }

        LeakCanary.config = LeakCanary.config.copy(
            onHeapAnalyzedListener = customListener,
            // 可一并自定义其他参数,例如最大重试次数
            maxStoredHeapDumps = 5
        )

        // 注意:不能再次调用 LeakCanary.install,否则会重复初始化
    }
}

3.3.3 延迟初始化

需要禁用自动安装,再手动在合适时机调用:

// 在 Application 的 onCreate 最开始禁用自动安装
LeakCanary.config = LeakCanary.config.copy(
    // 若不想使用默认监听,可设为空或自定义
    onHeapAnalyzedListener = OnHeapAnalyzedListener { /* noop */ }
)
// 随后在延迟点(如首次 Activity onResume)再真正安装
// 注意:延迟安装需在非 analyzer 进程中执行
if (!LeakCanary.isInAnalyzerProcess) {
    // 使用 Handler 延迟 2 秒后安装
    Handler(mainLooper).postDelayed({
        LeakCanary.install(application)
    }, 2000)
}

3.4 调试与验证

  • Log 关键字:在 Logcat 中过滤 "LeakCanary",查看是否有 "LeakCanary is enabled" 或 "Installing LeakCanary" 日志。
  • 断点检查:在自定义监听器的回调中设置断点,验证泄漏分析时是否进入自定义逻辑。
  • 耗时测量:在 Application 的 onCreate 开始和结尾记录时间戳,对比延迟初始化和自动安装的启动耗时差异。

3.5 常见错误与避坑

⚠️ 重复初始化
手动调用 LeakCanary.install() 时必须确保全局只执行一次。若同时使用了默认自动安装和手动安装,会导致二次初始化,可能引发 IllegalStateException。建议在延迟初始化时先设置 LeakCanary.config = … 并标记已初始化状态。
💡 关键原则
LeakCanary.config 的赋值操作必须在 LeakCanary.install() 之前完成。如果先调用了 install(),后续的 config 修改将不会生效。最佳实践是在 Application 的 onCreate 最顶部设置 config。
  • ContentProvider 冲突:如果项目中也自定义了 ContentProvider,注意其优先级和进程隔离,避免 LeakCanary 的 ContentProvider 被主进程以外的 Context 调用。
  • 线程安全问题:在延迟初始化时如果使用异步线程执行,需确保在 UI 线程调用 LeakCanary.install,因为 LeakCanary 内部依赖主线程的 Handler。

3.6 性能与稳定性优化

  • 启动耗时优化:自动安装会在 ContentProvider 中执行耗时较短的初始化,但依然增加了 Zygote 后的启动路径。延迟初始化可将此部分移至用户可见的首帧之后,对冷启动时间敏感的应用推荐使用。
  • 进程隔离:LeakCanary 会创建独立的分析进程 leakcanary。初始化时通过 LeakCanary.isInAnalyzerProcess 判断,避免重复初始化。
  • 最小配置原则:自定义监听时避免在回调中执行长时间操作,否则会阻塞分析队列。如需上报,采用异步任务。

3.7 初始化决策流程图

LeakCanary 初始化配置决策流程 LeakCanary 初始化配置决策流程 Application.onCreate 自动安装? ContentProvider 自动初始化 安装完成 手动设置 LeakCanary.config 延迟? 延迟到 用户交互后 安装完成 三种初始化策略的关键节点 • 自动安装:无代码侵入,适合调试环境,但会略微增加启动时间。 • 自定义监听:通过修改 LeakCanary.config 实现定制化分析结果处理,适用于上报、日志等。 • 延迟初始化:在 Application.onCreate 中手动设置 config 并推迟 install() 调用, 可有效降低冷启动时间,适合生产环境或对启动性能敏感的场景。

3.8 部署建议

  • 在 Release 包中务必移除或禁用 LeakCanary 依赖,或通过 build 变体(如 debugImplementation)仅在调试版本生效。
  • 若需在 Release 包保留(例如灰度检测),确保关闭自动安装并在用户无感知时机延迟初始化,且自定义监听中不包含敏感日志。