Android实现工作线程(二)

93 阅读3分钟

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

要创建一个工作线程,我们可以继承HandlerThreadThread。这使事情变得容易得多。原因是它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 的地方。