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);
}