likes
comments
collection
share

android基础 Handler源码解析

作者站长头像
站长
· 阅读数 54

1.发送消息

public final boolean sendMessage(@NonNull Message msg) {
    return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public final boolean post(@NonNull Runnable r) {
   return  sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}
  1. 发送消息最终都会调用sendMessageDelayed() -> sendMessageAtTime()。
  2. post(Runnable)会调用getPostMessage(r),构建一个Message对象,把Runable设置为msg的 callback。(在handler处理消息时会用到msg.callback)
  3. sendMessageAtTime()的第二个参数为消息执行的时间,SystemClock.uptimeMillis() + delayMillis 为系统启动时间+delatTime。当手动修改系统时间后,Handler消息处理不会出现异常。
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    ......
    return enqueueMessage(queue, msg, uptimeMillis);
}
```
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
        long uptimeMillis) {
     //--1
    msg.target = this;
    msg.workSourceUid = ThreadLocalWorkSource.getUid();

    if (mAsynchronous) {
        msg.setAsynchronous(true);
     }
    //--2
    return queue.enqueueMessage(msg, uptimeMillis);
}
  1. 给Message设置target为当前Handler对象。
  2. 将msg放入mQueue中,mQueue是在Handler()的构造方法中初始化,获取的是mLooper.mQueue,具体类型为MessageQueue
boolean enqueueMessage(Message msg, long when) {
    //--1
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }

    synchronized (this) {
        ......
        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        //--2
        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}
  1. 判断message.target 如果为空,则抛出IllegalArgumentException异常,通过Handler sendMessgae 都会把当前handler对象设置为message的target。
  2. 通过MessageQueue.postSyncBarrier()可以发送一个target为空的同步消息,称之为同步屏障。用于阻隔所有同步消息的执行。在ViewRootImpl的scheduleTraversal()中就会发出一个同步屏障,用于保证ui绘制的优先执行 3.根据Message执行时间排序,把先执行的Message放在队列前边

2.启动消息循环

public static void prepare() {
    prepare(true);
}
```
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));
}
```
public static void loop() {
    ......
}
ThreadLocal.java
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}
  1. 调用Loope.prepare() 和Looper.loop()即可在一个Thread中启动启动消息循环
  2. 每个Thread只有一个Looper和一个MessageQueue,可以有多个Handler。保证每个线程只有一个Looper和MessageQueue是由ThreadLocal机制实现。在preapre()中,new了一个Looper设置给了sThreadLocal对象,可以看到,最终是以threadLocal为key,Looper为value,存储在了Thread的成员变量threadLocals中。

3.消息循环

Looper.java
public static void loop() {
    ......
    me.mInLoop = true;
    final MessageQueue queue = me.mQueue;
    ......
    boolean slowDeliveryDetected = false;
    //--1
    for (;;) {
        //--2
        Message msg = queue.next();// might block
        //--3
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
        ......
        //--4
        msg.target.dispatchMessage(msg)

        ......
        msg.recycleUnchecked();
    }
}
  1. 在loop()中,开启了一个死循环,遍历MessageQueue中的消息
  2. queue.next(),当没有消息循环时,会在MessageQueue.next()中挂起。loop()中的循环不会结束。
  3. 只有当MessageQueue停止后,loop()中的死循环才会return
  4. 当获取到消息后,会调用msg.target,dispatchMessage(msg),处理消息。target即为Handler对象
Message next() {
    ......
    for (;;) {
        //--1
        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            // Try to retrieve the next message.  Return if found.
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
             //--2
            if (msg != null && msg.target == null) {
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    // Next message is not ready.  Set a timeout to wake up when it is ready.
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // Got a message.
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;
                }
            } else {
                // No more messages.
                nextPollTimeoutMillis = -1;
            }
            ......
        // Run the idle handlers.
        // We only ever reach this code block during the first iteration.
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler

            boolean keep = false;
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }

            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }
        ......
    }
}
  1. 在next()中开启了一个死循环,调用了nativePollOnce(ptr, nextPollTimeoutMillis),当消息循环队列为空时,这个方法会通过底层epoll机制,使当前线程挂起,当有新消息时,会重新唤醒消息队列,不会使当前线程阻塞。
  2. 判断当msg != null && msg.target == null时,即当前消息为同步屏障时,阻塞当前MessageQueue中的同步消息的分发。同时异步消息可以正常执行。
  3. 当执行完MessageQueue中消息后,会执行IdleHandler中的queueIdle(),其返回值表示是否在下次MessageQueue空闲时再次执行

4.消息处理

public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

1.Handler分发处理消息的优先级为msg.callBack > mCallBack > HandleMessage()

5.其他

1.Handler.sendMessageAtFrontOfQueue()在消息队列头部添加一条Message

2.Handler.removeCallbacksAndMessages(null)删除MessageQueue中的所有Message

3.Looper.setMessageLogging(Printer)设置日志打印,在message分发时会输出相应log

转载自:https://juejin.cn/post/7096355472881483783
评论
请登录