ThreadPolicy 检测规则详解

原理与核心思想

ThreadPolicy 是 StrictMode 针对主线程(UI 线程)性能问题的监控策略。Android 系统要求主线程专注于 UI 绘制与事件分发,任何耗时的同步操作(如磁盘 I/O、网络请求)都会导致界面卡顿甚至 ANR。 ThreadPolicy 通过 Hook 底层库调用(如 java.io.File、java.net.Socket),在应用执行这些危险操作时立即触发警告,帮助开发者在开发阶段发现并修复隐患。

四大检测规则与阈值

规则方法 检测目标 阈值配置 触发特征
detectDiskReads() 主线程发起文件或共享偏好读取 无阈值,一旦调用立即触发 日志标记 disk-read
detectDiskWrites() 主线程发起文件或数据库写入 无阈值,一旦调用立即触发 日志标记 disk-write
detectNetwork() 主线程发起 HTTP/Socket 请求 无阈值,一旦调用立即触发 日志标记 network
detectCustomSlowCalls() 主线程执行自定义耗时方法 需配合 Looper.setSlowLogThresholdMs() 日志标记 custom-slow-call
阈值规则提示: 系统对 Disk、Network 采取零容忍策略,只要在主线程发生就记录违规。而 detectCustomSlowCalls 属于框架层检测,必须通过 Looper 设置耗时阈值(如 200ms),低于阈值的方法不会触发。

实现流程与代码配置

在 Application 或入口 Activity 的 onCreate 中构建 ThreadPolicy,分四步完成:创建 Builder、注册检测规则、设置惩罚措施、应用策略。

// 步骤1:构建 ThreadPolicy
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
        // 步骤2:注册检测规则
        .detectDiskReads()
        .detectDiskWrites()
        .detectNetwork()
        .detectCustomSlowCalls()
        // 步骤3:设置惩罚(支持组合使用)
        .penaltyLog()
        .penaltyFlashScreen()
        .build();
// 步骤4:应用策略
StrictMode.setThreadPolicy(policy);

自定义慢调用阈值配置

detectCustomSlowCalls 依赖 Looper 的耗时阈值。需要在 Looper 所在线程(即主线程)初始化时设置,推荐放在 Application 的 attachBaseContext 或 onCreate 中。

// 设置慢调用阈值:主线程消息处理超过 200ms 记录慢日志,超过 100ms 记录警告
Looper.myLooper().setSlowLogThresholdMs(200, 100);
调试与验证: 设置完成后,通过 adb 命令开启 StrictMode 日志标记。
adb shell setprop debug.strictmode.log 1
adb shell setprop debug.strictmode.vm 1
运行时过滤:logcat | grep StrictMode,可追踪违规堆栈与发生线程。

常见错误与避坑

  • 忽略自定义调用阈值: 只配置了 detectCustomSlowCalls 但未调用 setSlowLogThresholdMs,导致所有方法都不触发违规。
  • 生产环境误用 penaltyDeath: penaltyDeath 会使应用在违规时直接崩溃,严禁在 Release 版本开启,仅用于 Debug 调试。
  • 策略未全局生效: 只在 Activity 中配置而 Application 中遗漏,会导致未覆盖的 Service 或 BroadcastReceiver 仍无法被监控。
  • 第三方库误报: 某些第三方 SDK 可能在主线程进行少量 I/O,可通过 penaltyLog 收集日志后针对性添加白名单或延迟初始化。

性能与稳定性优化建议

  • 分层惩罚: Debug 版本使用 penaltyLog + penaltyFlashScreen,Release 版本仅保留 penaltyLog 或完全关闭。
  • 结合 VM Policy: ThreadPolicy 负责线程耗时,VmPolicy 负责资源泄露,两者配合形成完整防护网。
  • 汇总分析: 定期收集 Crash 平台中的 StrictMode 日志,归类汇总主线程违规最多的 Top 10 操作,纳入技术改进专项。

核心流程框架图

ThreadPolicy 检测规则执行流程 Application.onCreate ThreadPolicy.Builder detectDiskReads / detectDiskWrites detectNetwork / detectCustomSlowCalls penaltyLog / penaltyDialog 主线程运行时 Hook 监控 触发违规 → 输出日志 / 弹窗 / 预防ANR 💡 提示: diskRead/Write/Network 无阈值,立即触发。 customSlowCall 需 setSlowLogThresholdMs
边界案例提醒:
  • 若在主线程中使用了 SharedPreferences 的 apply() 方法,系统会检测到 disk-write 违规(因为 apply() 虽然异步写文件,但会在主线程进行 commit 前的 writeToFile 操作)。
  • detectCustomSlowCalls 仅在 Looper 消息处理超时时触发,不适用于 Thread 或 AsyncTask 中新开的线程。