我们知道在编程时许多操作 (如更新 UI) 需要在主线程中完成, 而且, 耗时操作 (如网络连接) 需要放在子线程中, 否则会引起 ANR 所以我们常使用 Handler 来实现线程间的消息传递, 这里讨论的也就是 Handler 的运行机制
Handler 的运行主要由两个类来支撑: Looper 与 MessageQueue 熟悉开发的朋友都知道在子线程中默认是无法创建 Handler 的, 这是因为子线程中不存在消息队列当需要创建一个与子线程绑定的 Handler 时, 标准代码如下:
- class LooperThread extends Thread {
- public Handler mHandler;
- public void run() {
- Looper.prepare();
- mHandler = new Handler() {
- public void handleMessage(Message msg) {
- // process incoming messages here
- }
- };
- Looper.loop();
- }
- }
在创建 Handler 前, 需要先调用 Looper.prepare()方法, 之后再调用 Looper.loop()方法也就是说 Handler 的功能实现建立在 Looper 之上
- static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
- final MessageQueue mQueue;
- final Thread mThread;
- 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));
- }
- private Looper(boolean quitAllowed) {
- mQueue = new MessageQueue(quitAllowed);
- mThread = Thread.currentThread();
- }
由于 Looper 的消息循环是一个死循环, 一个线程最多只能有一个 Looper, 所以 Looper.prepare()函数首先检查该线程是否已经拥有一个 Looper, 如果有则抛出异常 Looper 通过 ThreadLocal 类为每个线程储存独立的 Looper 实例, 简单说一下 ThreadLocal 的实现原理:
Java 并发编程: 深入剖析 ThreadLocal
首先, 在每个线程 Thread 内部有一个 ThreadLocal.ThreadLocalMap 类型的成员变量 threadLocals, 这个 threadLocals 就是用来存储实际的变量副本的, 键值为当前 ThreadLocal 变量, value 为变量副本
初始时, 在 Thread 里面, threadLocals 为空, 当通过 ThreadLocal 变量调用 get()方法或者 set()方法, 就会对 Thread 类中的 threadLocals 进行初始化, 并且以当前 ThreadLocal 变量为键值, 以 ThreadLocal 要保存的副本变量为 value, 存到 threadLocals
然后在当前线程里面, 如果要使用副本变量, 就可以通过 get 方法在 threadLocals 里面查找
- public static void loop() {
- final Looper me = myLooper();
- if (me == null) {
- throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
- }
- final MessageQueue queue = me.mQueue;
- for (;;) {
- Message msg = queue.next(); // might block
- if (msg == null) {
- // No message indicates that the message queue is quitting.
- return;
- }
- msg.target.dispatchMessage(msg);
- msg.recycleUnchecked();
- }
- }
在 4 行可以看到一个我们熟悉的异常信息, 说明并没有 Looper 与当前线程相关联, 也就无法进行消息传递 Looper.loop()方法本身是一个死循环, 不断在 MessageQueue 中取出 Message 对象进行处理, 然后调用 Message.recycleUnchecked()方法对其回收, 这也是为什么官方推荐使用 Message.obtain()方法来获取 Message 实例, 而不是直接新建对象当没有消息可处理时, MessageQueue.next()方法将阻塞, 直到新的消息到来
对于 MessageQueue, 我们只需要关注两个函数即可, 一个是 MessageQueue.enqueueMessage()另一个是 MessageQueue.next(), 它们分别对应着队列的插入与取出操作 MessageQueue 中队列是使用单链表实现的, 由 Message.next 属性指向其下一个元素
- boolean enqueueMessage(Message msg, long when) {
- synchronized (this) {
- msg.markInUse();
- msg.when = when;
- Message p = mMessages;
- boolean needWake;
- if (p == null || when == 0 || when < p.when) {
- msg.next = p;
- mMessages = msg;
- } else {
- Message prev;
- for (;;) {
- prev = p;
- p = p.next;
- if (p == null || when < p.when) {
- break;
- }
- }
- msg.next = p; // invariant: p == prev.next
- prev.next = msg;
- }
- }
- return true;
- }
向 MessageQueue 中插入元素时, 需要根据 Message.when 属性的大小决定插入的位置, 它代表了 Meesage 需要被处理的时间, 拿 Handler.sendMessage()函数为例
- public final boolean sendMessage(Message msg) {
- return sendMessageDelayed(msg, 0);
- }
- public final boolean sendMessageDelayed(Message msg, long delayMillis) {
- if (delayMillis < 0) {
- delayMillis = 0;
- }
- return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
- }
- public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
- MessageQueue queue = mQueue;
- return enqueueMessage(queue, msg, uptimeMillis);
- }
- private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
- msg.target = this;
- if (mAsynchronous) {
- msg.setAsynchronous(true);
- }
- return queue.enqueueMessage(msg, uptimeMillis);
- }
从调用流程来看, Handler.sendMessage()函数其实就是向 MessageQueue 的消息队列中插入了一个 Message.when 属性为当前时间的元素
对于 MessageQueue.next()函数, 简单来说它的作用就是在 MessageQueue 的头部取出元素, 然后执行 Handler.dispatchMessage()函数
- public void dispatchMessage(Message msg) {
- if (msg.callback != null) {
- handleCallback(msg);
- } else {
- handleMessage(msg);
- }
- }
- private static void handleCallback(Message message) {
- message.callback.run();
- }
如果我们使用 Handler.post()函数发送一个 Runnable 对象, 那么最终 Runnable 对象会在 Handler.handleCallback()函数中执行如果是一个普通 Message, 那么它会被分发到一个我们熟悉的函数中, Handler.handleMessage(), 这就是为什么一般我们都需要重写这个函数对消息进行处理
来源: https://www.cnblogs.com/mmmmar/p/8595723.html