持续创作,加速成长!这是我参与「掘金日新计划 · 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
的地方。