HandlerThread

首先在UI线程创建了一个Handler实例对象,无论是匿名内部类还是自定义类生成的Handler实例对象,我们都需 要对handleMessage方法进行重写,在handleMessage方法中我们可以通过参数msg来写接受消息过后UI线程的逻辑处理,接着我们创建子线程,在子线程中需要更新UI的时候,新建一个Message对象,并且将消息的数据记录在这个消息对象Message的内部,比如arg1,arg2,obj等,然后通过前面的Handler实例对象调用sendMessge方法把这Message实例对象发送出去,之后这个消息会被存放于MessageQueue中等待被处理,此时MessageQueue的管家Looper正在不停的把MessageQueue存在的消息取出来,通过回调dispatchMessage方法将消息传递给Handler的handleMessage方法,最终前面提到的消息会被Looper从MessageQueue中取出来传递给handleMessage方法。

作者:循环不息优化不止
链接:https://juejin.cn/post/7549637439360663578
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


1. HandlerThread 是什么?

普通 Thread 默认没有 Looper,所以不能直接配合 Handler 持续接收消息。

HandlerThread 本质上是:

Thread + Looper + MessageQueue

它启动后,内部会创建一个 Looper,然后不断从 MessageQueue 中取消息执行。

简单理解:

HandlerThread 是一个可以用 Handler 投递任务的后台线程。


2. 基本用法

Java 示例

HandlerThread handlerThread = new HandlerThread("work-thread");
handlerThread.start();

Handler workerHandler = new Handler(handlerThread.getLooper());

workerHandler.post(new Runnable() {
    @Override
    public void run() {
        // 这里运行在 HandlerThread 子线程中
        // 可以执行耗时操作
        doSomething();
    }
});

停止线程:

handlerThread.quitSafely();

3. Kotlin 示例

val handlerThread = HandlerThread("work-thread")
handlerThread.start()

val workerHandler = Handler(handlerThread.looper)

workerHandler.post {
    // 这里是子线程
    doSomething()
}

停止:

handlerThread.quitSafely()

4. 为什么要用 HandlerThread?

1)避免阻塞主线程

Android 主线程负责:

  • UI 绘制
  • 用户点击响应
  • Activity 生命周期
  • View 更新

如果在主线程做耗时操作,比如:

Thread.sleep(3000);
readLargeFile();
decodeBitmap();

就可能造成:

  • 界面卡顿
  • ANR
  • 用户点击无响应

所以需要把耗时任务放到子线程。


2)比普通 Thread 更适合处理多个任务

普通线程通常这样用:

new Thread(() -> {
    doSomething();
}).start();

问题是:

每来一个任务就创建一个线程,成本较高,而且不好管理。

HandlerThread 可以复用同一个线程:

workerHandler.post(task1);
workerHandler.post(task2);
workerHandler.post(task3);

这些任务会在同一个后台线程中按顺序执行。


3)天然支持消息队列

HandlerThread 里面有 MessageQueue

所以可以:

workerHandler.postDelayed(() -> {
    doSomething();
}, 1000);

也可以发送消息:

Message msg = workerHandler.obtainMessage();
msg.what = 1;
workerHandler.sendMessage(msg);

这比普通线程更适合做异步消息处理。


5. HandlerThread 的工作原理

大概流程是:

HandlerThread thread = new HandlerThread("test");
thread.start();

调用 start() 后,内部会执行它的 run() 方法:

@Override
public void run() {
    Looper.prepare();
    mLooper = Looper.myLooper();
    Looper.loop();
}

核心就是三步:

Looper.prepare(); // 创建 Looper 和 MessageQueue
Looper.loop();    // 开启消息循环

然后你创建 Handler:

Handler handler = new Handler(handlerThread.getLooper());

这个 Handler 就绑定到了 HandlerThreadLooper

之后:

handler.post(runnable);

任务会进入这个线程的消息队列,然后在 HandlerThread 中执行。


6. 为什么不能直接在普通 Thread 里 new Handler?

比如:

new Thread(() -> {
    Handler handler = new Handler();
}).start();

很多时候会报错:

Can't create handler inside thread that has not called Looper.prepare()

原因是:

普通子线程默认没有 Looper

如果你硬要用普通线程,也可以这样:

new Thread(() -> {
    Looper.prepare();

    Handler handler = new Handler();

    Looper.loop();
}).start();

但这样写麻烦,而且需要自己管理生命周期。

所以 Android 提供了 HandlerThread 帮你封装好。


7. HandlerThread 和主线程 Handler 的区别

主线程本身就有 Looper,所以可以直接:

Handler mainHandler = new Handler(Looper.getMainLooper());

这个 Handler 执行任务在主线程。

HandlerThread 是子线程,需要先:

handlerThread.start();

然后再获取:

handlerThread.getLooper();

区别:

类型 执行线程 用途
Handler(Looper.getMainLooper()) 主线程 更新 UI
HandlerThread + Handler 子线程 执行后台任务

8. 典型使用场景

HandlerThread 适合:

  • 串行执行后台任务
  • 文件读写
  • 数据库操作
  • 图片解码
  • 蓝牙、相机、音视频处理
  • 需要延迟执行的后台任务
  • 不想频繁创建线程的场景

例如相机处理中经常会用:

HandlerThread cameraThread = new HandlerThread("CameraThread");
cameraThread.start();

Handler cameraHandler = new Handler(cameraThread.getLooper());

这样相机相关操作就在后台线程执行,不会卡 UI。


9. 注意事项

1)用完要退出

否则线程会一直存活。

handlerThread.quitSafely();

通常在 onDestroy() 里调用:

@Override
protected void onDestroy() {
    super.onDestroy();
    handlerThread.quitSafely();
}

2)不能在子线程直接更新 UI

错误:

workerHandler.post(() -> {
    textView.setText("完成");
});

因为这段代码运行在子线程。

正确方式:

Handler mainHandler = new Handler(Looper.getMainLooper());

workerHandler.post(() -> {
    String result = doSomething();

    mainHandler.post(() -> {
        textView.setText(result);
    });
});

3)任务是串行执行的

HandlerThread 只有一个线程,所以任务会一个一个执行:

task1 -> task2 -> task3

如果你需要多个任务并发执行,应该考虑:

  • ThreadPoolExecutor
  • Kotlin Coroutine
  • RxJava
  • WorkManager

10. 简单总结

HandlerThread 的作用是:

创建一个带有消息循环的子线程,让我们可以用 Handler 向这个子线程发送任务。

为什么要用它?

因为:

  1. 避免主线程卡顿;
  2. 可以复用一个后台线程;
  3. 任务按顺序执行;
  4. 支持延迟任务和消息机制;
  5. 比自己手写 Thread + Looper 更方便。

一句话:

HandlerThread 就是 Android 帮你封装好的「带消息队列的后台线程」。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇