Handler
相关类
- Looper: 一个线程可以产生一个 Looper 对象,由它来管理此线程里的 MessageQueue( 消息队列 )和对消息进行循环。
- Handler: 你可以构造 Handler 对象来与 Looper 沟通,以便 push 新消息到 MessageQueue 里 ; 或者接收 Looper 从 MessageQueue 取出 所送来的消息。
- Message Queue( 消息队列 ): 用来存放线程放入的消息。
- Message:是线程间通讯的消息载体。两个码头之间运输货物,Message充当集装箱的功能,里面可以存放任何你想传递的消息。
关系
- 一个Thread对应多个Handler,一个Thread对应一个Looper和MessageQueue
- Handler与Thread共享Looper和MessageQueue
- Message只是消息的载体,将会被发送到与线程绑定的唯一的MessageQueue中,并且被与线程绑定的唯一的Looper分发,被与其自身绑定的Handler消费。
调用流程
- 当我们调用handler.sendMessage(msg)方法发送一个Message时,实际上这个Message是发送到与当前线程绑定的一个MessageQueue中
- 然后与当前线程绑定的Looper将会不断的从MessageQueue中取出新的Message
- 调用msg.target.dispathMessage(msg)方法将消息分发到与Message绑定的handler.handleMessage()方法中。
HandlerThread
在线程(Thread)中,默认是没有Looper,需要手动添加。
官方提供HandlerThread类,方便创建一个拥有Looger实例的线程,结合Handler在子线程中执行耗时或延时等任务。
Handy class for starting a new thread that has a looper.
The looper can then be used to create handler classes.
Note that start() must still be called.
特点
- HandlerThread本质上是一个线程类,它继承了Thread
- 拥有自己的消息队列,它不会干扰或阻塞UI线程
- 拥有自己的内部Looper对象,可以进行looper循环
- 通过获取HandlerThread的looper对象传递给Handler对象,可以在handleMessage方法中执行异步任务
- 创建HandlerThread后必须先调用HandlerThread.start()方法,Thread会先调用run方法,创建Looper对象。
使用
class MainActivity : AppCompatActivity() {
private lateinit var handlerThread: HandlerThread
private lateinit var handler: Handler
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
handlerThread = HandlerThread(javaClass.simpleName)
handlerThread.start()
handler = Handler(handlerThread.looper) {
//处理消息
true
}
}
override fun onDestroy() {
super.onDestroy()
handler.removeCallbacksAndMessages(null)
handlerThread.quit()
}
}
退出循环
HandlerThread提供两个方法退出循环。
quit
将不在接受新的事件加入消息队列
清空MessageQueue中所有消息,无论是否是延迟消息
quitSafely
将不在接受新的事件加入消息队列
清空MessageQueue中所有的延时消息
API 18 引入
区别:清空消息之前会派发所有的非延迟消息
/**
* Quits the looper.
* <p>
* Causes the {@link #loop} method to terminate without processing any
* more messages in the message queue.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p class="note">
* Using this method may be unsafe because some messages may not be delivered
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
* that all pending work is completed in an orderly manner.
* </p>
*
* @see #quitSafely
*/
public void quit() {
mQueue.quit(false);
}
/**
* Quits the looper safely.
* <p>
* Causes the {@link #loop} method to terminate as soon as all remaining messages
* in the message queue that are already due to be delivered have been handled.
* However pending delayed messages with due times in the future will not be
* delivered before the loop terminates.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p>
*/
public void quitSafely() {
mQueue.quit(true);
}