Handler 中的 handleMessage 所在線程是由什麼決定的?

大多數狀況下,handleMessage所在線程和 handler 初始化所在的線程相同,但 handler 初始化的時候能夠傳入一個 Looper 對象,此時handleMessage所在線程和參數looper所在線程相同。java

1. 含參構造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

2. 無參構造

若是使用無參的 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()能夠獲取)

3. 一個線程能夠有多少個 Looper?Handler 和 Looper 之間如何關聯?

3.1 一個線程能夠有多少個 Looper

查看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,這其中包含了一個消息隊列

3.2 Handler 和 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 了。隊列

相關文章
相關標籤/搜索