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 了。队列

相关文章
相关标签/搜索