大多數狀況下,handleMessage
所在線程和 handler 初始化所在的線程相同,但 handler 初始化的時候能夠傳入一個 Looper 對象,此時handleMessage
所在線程和參數looper
所在線程相同。java
public Handler(Looper looper)
class MainActivity : AppCompatActivity() { var handler: Handler? = null var looper: Looper? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) looper = Looper.getMainLooper() val thread = object : Thread() { override fun run() { super.run() Log.e("abc", "--- Runnable:threadName ---" + Thread.currentThread().name) handler = object : Handler(looper) { override fun handleMessage(msg: Message?) { super.handleMessage(msg) Log.e("abc","--- handleMessage:threadName ---" + Thread.currentThread().name ) } } } } thread.start() myBtn.setOnClickListener { val msg = Message() handler!!.sendMessage(msg) } } } // log 打印狀況 --- Runnable:threadName ---Thread-2 --- handleMessage:threadName ---main
從 log 中能夠看到 handler 初始化所在線程在 Thread-2,而handleMessage
所在的線程是主線程main
.ide
若是使用無參的 Handler 初始化構造,須要手動調用Looper.prepare()
和Looper.loop()
:oop
val thread = object : Thread() { override fun run() { super.run() Log.e("abc", "--- Runnable:threadName ---" + Thread.currentThread().name) Looper.prepare() handler = object : Handler() { override fun handleMessage(msg: Message?) { super.handleMessage(msg) Log.e( "abc", "--- handleMessage:threadName ---" + Thread.currentThread().name ) } } Looper.loop() } } // log 打印狀況 --- Runnable:threadName ---Thread-2 --- handleMessage:threadName ---Thread-2
不手動調用Looper.prepare()
會拋出異常:post
java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-2,5,main] that has not called Looper.prepare()
主線程中使用 Handler:
大多數時候咱們不會在子線程中初始化和使用 handler,而是在主線程中使用,此時不須要prepare()
和loop()
,由於主線程中自帶一個 Looper(經過Looper.getMainLooper()
能夠獲取)
查看Looper.prepare()
源碼:ui
private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
繼續查看sThreadLocal.set(new Looper(quitAllowed))
:this
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
Threadlocal 是一個線程內部的存儲類,能夠在指定線程內存儲數據,數據存儲之後,只有指定線程能夠獲得存儲數據。在這裏 ThreadLocal 的做用是保證了每一個線程都有各自的 Looper,就是說 一個線程只能有一個 Looper,關於 Threadlocal,能夠看看這篇文章 Threadlocal
接下來看看建立 Looper 實例的方法new Looper(quitAllowed)
:線程
final MessageQueue mQueue; final Thread mThread; private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread();
在構造方法裏,初始化 了MessageQueue 和表明當前線程的屬性 mThread.code
調用
Looper.prepare()
其實就是利用 ThreadLocal 爲當前的線程建立了一個獨立的 Looper,這其中包含了一個消息隊列
一個線程只能有一個 Looper,但一個線程中能夠建立多個 Handler,那麼一個 Looper 怎麼和多個 Handler 對應呢?查看源碼可知,post(Runnable r)
、postDelayed(Runnable r, long delayMillis)
、postAtTime(Runnable r, long uptimeMillis)
和sendMessage
最終調用的都是enqueueMessage
方法:對象
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
msg.target = this
這裏就是將當前的 Handler 賦值給 Message 對象的 target 屬性,這樣在處理消息的時候經過msg.target
就能夠區分開不一樣的 Handler 了。隊列