后台HandlerThread 使用的问题

1. 背景

在实际项目开发中,经常会有这样的一些阻塞操作,如:

  • 本地文件 I/O 操作
  • 一些计算密集比较耗时的操作
  • 网络请求操作
  • 某些第三方SDK的初始化比较耗时

对于以上这些场景的场景,他们的共有特性是比较耗时,放在主线程会导致主线程的UI卡顿;同时这些又是一些低频无规律零散的操作,每一次都进行线程的创建执行的话则会造成性能问题。

对于以上问题,常见的处理分为两种情况:

  1. 使用一个线程池来处理
  2. 使用HandlerThread + Handler 来处理。

以上线程池的方案不做特殊讨论了,仅讨论HandlerThread 的方法。

2. 问题现象

有时候,会遇到一些看起来非常奇怪的问题,例如以下代码:

1
2
3
4
5
6
7
8
9
// 1. 向一个独立线程的Handler中发送一个 Runnable来执行
backHandler.post(new Runnable(){
@Override
public voud run() {
// 2. 一些耗时操作,不能放在主线程
}
});

以上代码在我们的项目中非常常见,前端时间遇到了一个奇怪的现象,通过debug工具发现:

1
以上代码中1处执行了,而2处没有执行

3. 问题分析

这个问题看起来非常反直觉,因为直觉告诉我们向HandlerThread中post 的Runnable一定会执行的。但是,事实上却不见得。在这里,我们先提出一个问题:

1
如果和一个Handler关联的线程(HandlerThread)由于某些原因退出了,那么随后给它的消息队列中发送消息的话还会被处理吗?

上面的问题先暂时放一下,我们接着来分析上一章节中出现的问题,要分析问题,先从源码下手。

4. 解决方案

涉及到后台的任务,根据需要使用如下替代方案:

  • 后台线程池,使用线程池能保证某一个线程在异常退出后能够有新的线程补充进来。
  • 使用 WorkManager 接口。
  • 在HandlerThread 的 run() 方法外侧添加 try catch 方法来捕获异常,以免该线程异常退出。
坚持原创技术分享,您的支持将鼓励我继续创作!