持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第30天,点击查看活动详情
前言
上一篇我们了解线程的基础和自定义线程进行手动管理,接下来我们了解Looper版本和HandlerThread版本。
Looper 版本
Looper类:它将普通线程(在其run方法完成时被销毁)转换为只要 Android应用程序还活着就可以保持活动状态的线程,它自己有一个要执行的任务队列。
Handler类:我们不能直接将任务添加到 Looper 的队列中。相反,我们应该使用Handler来解决问题。换句话说,我们使用 Handler 将任务添加到Looper 的队列中。
才艺展示:
class LooperWorkerThread : Thread() {
private lateinit var handler: Handler
init {
start()
}
override fun run() {
// 在当前线程上准备一个Looper。隐式检测当前线程
Looper.prepare()
// 将 Handler 附加到当前线程的 Looper
handler = Handler(Looper.myLooper())
// 在以下行之后,该线程将启动
// 运行消息循环并且不会正常
// 退出循环,除非发生问题或您
// 调用退出()
Looper.loop()
}
fun execute(block: () -> Unit) {
handler.post { block() }
}
fun quit() {
Looper.myLooper()?.quit()
}
}
关于上述实现的几点说明:
- 要将普通线程转换为可以永久运行的线程,我们需要调用
Looper.prepare()然后Looper.loop()。此外,prepare应始终start在线程的方法之后调用。否则会抛出异常。 - 为了与
Looper的队列通信,我们创建了一个实例Handler并将当前线程的Looper传递给Handler。 - 要将任务添加到
Looper的队列中,我们调用Handler.post()并传递一个Runnable. - 当我们完成工作线程时,我们应该调用该quit方法来停止其关联的
Looper。 我们可以LooperWorkerThread像使用HandcraftedWorkerThread.
通过这个实现,我们消除了繁忙的等待,也摆脱了手动管理任务队列。我们仍然可以做得比这更好!
HandlerThread版本
要创建一个工作线程,我们可以继承HandlerThread自Thread。这使事情变得容易得多。原因是它HandlerThread有一个内部Looper,所以我们不需要手动创建一个。
class HandlerWorkerThread(threadName: String) : HandlerThread(threadName) {
private lateinit var handler: Handler
init {
start()
}
override fun onLooperPrepared() {
handler = Handler()
}
fun execute(block: () -> Unit) {
if (::handler.isInitialized) {
handler.post { block() }
}
}
}
关于上面代码的一些注释:
- 如前所述,因为
HandlerThread有一个内部Looper,所以不需要显式创建一个。 - 为了与
Looper进行通信,HandlerThread我们创建了一个Handler。请注意,当我们创建Handler的实例而不将Looper传递给其构造函数时,Handler会隐式使用当前线程的Looper。在这里,Handler将与HandlerThread. - 我们在内部进行检查
execute以确保handler在调用其post方法之前已对其进行了初始化。execute原因是,如果在调用回调之前调用任何机会,我们可以防止运行时错误onLooperPrepared。 - 我们已经在方法内部创建了
Handler onLooperPrepared。原因是我们应该只在准备好Looper时才创建Handler。当LooperHandlerThread准备好时,onLooperPrepared它会被调用,这就是我们实例化Handler的地方。