通常我们使用Handler时,直接在activity直接new handler使用,但是在子线程中并不能直接new 让然后使用。如果直接在子线程中直接new ,会出现如下的错误提示:
意思就是说:在没有调用Looper.prepare()之前不能在子线程创建Handler。
为什么在主线程中我们就已经可以直接创建Handler?
因为在Activity的启动代码中,已经在当前UI线程(主线程)调用了Looper.prepareMainLooper()和Looper.loop()方法。我们可以在源码的ActivityThread类中看到,如图:
从上图可以看出,在主线程中首先调用的是Looper.prepareMainLooper(),然后创建了一个ActivityThread实例,最后通过Looper类使主线程进入消息循环中。
如果在子线程中使用handler,必须要调用loop.prepare()和looper.loop()方法。
那这2个方法到底做了哪些事呢?
首先说Looper.prepare()
在调用 Looper.prepare() 方法时,创建一个 Looper 对象,这个对象是被 set 绑定到一个ThreadLocal(线程局部变量)中。
sThreadLocal.set(new Looper(quitAllowed)); ThreadLocal的作用就是保证每一个调用了prepare()函数的线程里面都有一个唯一的Looper对象。
而new Looper(quitAllowed)方法实际上也创建了消息队列MessageQueue,如下图:
再来说Looper.loop()
以下还有剩余未截全的,承接上面的
可以看出,这个方法就是不断从消息队列(MessageQueue)中取出消息,再调用handler.dispatchMessage()分发消息,如下图:
这个handleMessage方法就是我们使用handler时,经常重写的方法。
当然有些人说,在Loop.loop()方法中msg.target.dispatchMessage(msg),你怎么确定是handler的dispatchMessage方法呢?好吧,让你看下Message类中成员变量,如下图:
最后,有人会问,消息(Message)既然是从消息队列(MessageQueue)中取出来的,那消息(Message)是从哪进入消息队列(MessageQueue)的呢?
如下一组图:
直到最后一张图才看到,queue.enqueueMessage(msg, uptimeMillis);这就是消息进入消息队列的方法。
不管handler调用哪个方法发送消息,最终都会调用queue.enqueueMessage(msg, uptimeMillis);