android StrictMode 笔记

20 阅读3分钟

StrictMode 是 Android 开发中一个用于在开发阶段提前检测主线程违规操作和资源泄露的强大工具。它的核心价值在于 “主动发现”而非“事后排查”,能帮你将许多潜在的性能问题(如ANR、卡顿、内存泄露)扼杀在开发阶段。

📊 StrictMode 策略与场景一览

为了让你快速理解其应用方式,我将核心策略整理为下表:

策略类别检测内容核心场景与思路常见触发原因/示例
严格模式主线程磁盘I/O、网络操作等。场景:快速发现所有主线程违规。
思路:“零容忍”,在开发早期暴露所有问题。
SharedPreferences、数据库读写、文件流操作未放在子线程。
异步模式主线程网络请求、慢函数调用。场景:定位因网络请求、复杂计算导致的卡顿。
思路:针对性优化耗时瓶颈。
OkHttp/Retrofit同步调用、JSON解析、大量循环计算。
测试模式Activity、Service等实例泄露场景:自动化测试中防止资源泄露。
思路:确保测试用例的纯净与隔离。
未解注册BroadcastReceiver、单例持有Context引用。

🎯 核心使用场景详解

1. 检测主线程耗时操作 (ThreadPolicy)

这是预防ANR和界面卡顿的第一道防线。

// 推荐在 Application.onCreate() 中全局启用
if (BuildConfig.DEBUG) {
    StrictMode.setThreadPolicy(
        StrictMode.ThreadPolicy.Builder()
            .detectDiskReads()  // 检测磁盘读
            .detectDiskWrites() // 检测磁盘写
            .detectNetwork()    // 检测网络操作(主线程网络请求是重大错误)
            // .detectCustomSlowCalls() // 检测自定义慢函数
            .penaltyLog() // 触发时打印日志到Logcat
            .penaltyDeath() // 或 .penaltyDeathOnNetwork() 严重时直接崩溃,强迫修改
            .build()
    )
}

典型场景

  • 数据库操作:在主线程执行了RoomSQLite查询或写入。
  • 文件读写:访问SharedPreferences、读取缓存文件、写入日志。
  • 网络请求这是严重错误,必须使用OkHttp + Retrofit + 协程/RxJava异步处理。

2. 检测资源泄露 (VmPolicy)

主要用于检测ActivityServiceBroadcastReceiver等实例在预期生命周期结束后未被回收。

StrictMode.setVmPolicy(
    StrictMode.VmPolicy.Builder()
        .detectActivityLeaks()     // 检测Activity泄露
        .detectLeakedClosableObjects() // 检测未关闭的Closeable对象(如Cursor、FileInputStream)
        .detectLeakedSqlLiteObjects()  // 检测未关闭的SQLite对象
        .detectLeakedRegistrationObjects() // 检测未解注册的广播、服务连接等
        .penaltyLog()
        .build()
)

典型场景

  • 单例持有Context:单例类持有了Activity的引用。
  • 未关闭资源:打开CursorFileInputStream后未在finally块中关闭。
  • 监听器未解注册:在Activity中注册了广播、传感器监听器,但onDestroy时未解注册。

🛠️ 最佳实践与建议

  1. 仅限Debug模式:务必通过 if (BuildConfig.DEBUG) 包裹,绝不能在线上版本启用penaltyDeath()等策略,否则会导致用户应用崩溃。
  2. 分阶段启用:初期可以只启用.detectDiskWrites().detectNetwork()。随着代码规范提升,逐步加入更多检测项。
  3. 结合日志上报:可以自定义penaltyListener,将违规信息上报到开发者的错误收集系统(如BuglyFirebase Crashlytics),方便团队追溯。
  4. 集成到CI/CD:在自动化测试中启用StrictMode,一旦检测到违规,就让测试失败,确保代码质量。