Android 8.1 源码_机制篇 -- 全面解析 Handler 机制(原理篇)

栏目: 后端 · 发布时间: 5年前

内容简介:在整个 Android 的源码世界里,有两大利剑,其一是 Binder 机制,另一个便是 Handler 消息机制。消息机制涉及 MessageQueue/Message/Looper/Handler 这4个类。Handler 是 Android 中引入的一种让开发者参与处理线程中消息循环的机制。我们在使用 Handler 的时候与 Message 打交道最多,Message 是 Hanlder 机制向开发人员暴露出来的相关类,可以通过 Message 类完成大部分操作 Handler 的功能。作为一名程

开篇

核心源码

关键类 路径
Looper.java frameworks/base/core/java/android/os/Looper.java
Message.java frameworks/base/core/java/android/os/Message.java
MessageQueue.java frameworks/base/core/java/android/os/MessageQueue.java

简述

在整个 Android 的源码世界里,有两大利剑,其一是 Binder 机制,另一个便是 Handler 消息机制。消息机制涉及 MessageQueue/Message/Looper/Handler 这4个类。

Handler 是 Android 中引入的一种让开发者参与处理线程中消息循环的机制。我们在使用 Handler 的时候与 Message 打交道最多,Message 是 Hanlder 机制向开发人员暴露出来的相关类,可以通过 Message 类完成大部分操作 Handler 的功能。

作为一名程序员,我们不仅需要知道怎么用 Handler ,还要知道其内部如何实现的,这就是我写这篇文章的目的。

模型

消息机制(Handler)主要包含:

:sparkles: Message :消息分为硬件产生的消息(如按钮、触摸)和软件生成的消息;

:sparkles:  MessageQueue :消息队列的主要功能向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next);

:sparkles:  Handler :消息辅助类,主要功能向消息池发送各种消息事件(Handler.sendMessage)和处理相应消息事件(Handler.handleMessage);

:sparkles:  Looper :不断循环执行(Looper.loop),按分发机制将消息分发给目标处理者。

实例

/*
 * A typical example of the implementation of a Looper thread,
 * using the separation of {@link #prepare} and {@link #loop} to create an
 * initial Handler to communicate with the Looper.
 */
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();
    }
}

接下来我们就围绕这个实例展开讲解!

Looper

消息队列 MessageQueue 只是存储 Message 的地方,真正让消息队列循环起来的是 Looper,我们先来重点分析 Looper。

Looper 是用来使线程中的消息循环起来的。默认情况下当我们创建一个新的线程的时候,这个线程里面是没有消息队列 MessageQueue 的。为了能够让线程能够绑定一个消息队列,我们需要借助于 Looper :首先我们要调用 Looper 的 prepare() 方法,然后调用 Looper 的 Loop() 方法。

需要注意的是 Looper.prepare() 和 Looper.loop() 都是在新线程的 run 方法内调用的,这两个方法都是静态方法。

public static void prepare() {...}
    private static void prepare(boolean quitAllowed) {...}
    public static void loop() {...}

prepare()

我们来看一下 Looper.prepare(),该方法是让 Looper 做好准备,只有 Looper 准备好了之后才能调用 Looper.loop() 方法。

public static void prepare() {    
        prepare(true);     // 无参,调用 prepare(boolean quitAllowed)
    }
private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
        // 每个线程只允许执行一次该方法,第二次执行时已有 Looper,则会抛出异常!
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        // 创建 Looper 对象,并保存到当前线程的本地存储区
        sThreadLocal.set(new Looper(quitAllowed));      
    }

上面的代码首先通过 sThreadLocal.get() 拿到线程 sThreadLocal 所绑定的 Looper 对象,由于初始情况下 sThreadLocal 并没有绑定 Looper ,所以第一次调用 prepare 方法时,sThreadLocal.get() 返回 null,不会抛出异常。

ThreadLocal

ThreadLocal:线程本地存储区(Thread Local Storage,简称为 TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的TLS区域。

TLS 常用的操作方法:

set()

public void set(T value) {
        Thread t = Thread.currentThread();    // 获取当前线程 
        ThreadLocalMap map = getMap(t);       //查找当前线程的本地储存区
        if (map != null)
            map.set(this, value);             // 保存数据 value 到当前线程 this
        else
            createMap(t, value);
    }

我们看下 getMap() 函数:

ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

判断 map 是否为空,如果为空则创建 ThreadLocalMap :

void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

get()

public T get() {
        Thread t = Thread.currentThread();    // 获取当前线程 
        ThreadLocalMap map = getMap(t);       // 查找当前线程的本地储存区
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();   // 创建 ThreadLocalMap
    }

查看 setInitialValue() :

private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

Looper 通过如下代码保存了对当前线程的引用:

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();    // sThreadLocal 为 ThreadLocal 类型

所以在 Looper 对象中通过 sThreadLocal 就可以找到其绑定的线程。ThreadLocal 中有个 set 方法和 get 方法,可以通过 set 方法向 ThreadLocal 中存入一个对象,然后可以通过 get 方法取出存入的对象。

ThreadLocal 在 new 的时候使用了泛型,从上面的代码中我们可以看到此处的泛型类型是 Looper ,也就是我们通过 ThreadLocal 的 set 和 get 方法只能写入和读取 Looper 对象类型。

构造函数

源码中 Looper 的构造函数是 private 的,也就是在该类的外部不能用 new Looper() 的形式得到一个 Looper 对象。

private Looper(boolean quitAllowed) {...}

我们看下上面代码中 new Looper() 创建 Looper 对象的工作:

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);  // 创建 MessageQueue 对象
    mThread = Thread.currentThread();        // 记录当前线程
}

Looper.prepare()在每个线程只允许执行一次,该方法会创建 Looper 对象,Looper 的构造方法中会创建一个 MessageQueue 对象,再将 Looper 对象保存到当前线程 TLS。

prepareMainLooper()

另外,与 prepare() 相近功能的,还有一个 prepareMainLooper() 方法,该方法主要在 ActivityThread 类中使用。

public static void prepareMainLooper() {
        prepare(false);          // 设置不允许退出的 Looper
        synchronized (Looper.class) {
            // 将当前的 Looper 保存为主 Looper,每个线程只允许执行一次
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

loop()

Looper.loop()的代码如下:

/**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        final Looper me = myLooper();            // 获取当前线程绑定的 Looper 对象
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;    // 获取 Looper 对象中的消息队列

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        // 确保在权限检查时基于本地进程,而不是基于最初调用进程
        final long ident = Binder.clearCallingIdentity();

        for (;;) {     // 进入loop的主循环方法
            Message msg = queue.next(); // might block(可能会堵塞)
            if (msg == null) {          // 没有消息,则退出循环
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            // 默认为null,可通过 setMessageLogging() 方法来指定输出,用于 debug 功能
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;

            final long traceTag = me.mTraceTag;
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            final long end;
            try {
                msg.target.dispatchMessage(msg);       // 用于分发 Message
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (slowDispatchThresholdMs > 0) {
                final long time = end - start;
                if (time > slowDispatchThresholdMs) {
                    Slog.w(TAG, "Dispatch took " + time + "ms on "
                            + Thread.currentThread().getName() + ", h=" +
                            msg.target + " cb=" + msg.callback + " msg=" + msg.what);
                }
            }

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();     // 确保分发过程中 identity 不会损坏
            if (ident != newIdent) {
                // 打印 identity 改变的 log,在分发消息过程中是不希望身份被改变的
            }

            msg.recycleUnchecked();   // 将 Message 放入消息池
        }
    }

我们接下来会重点分析 loop() 里面的几个函数:

myLooper()

前面我们说过,在执行完了 Looper.prepare() 之后,我们就可以在外部通过调用 Looper.myLooper() 获取当前线程绑定的 Looper 对象。

public static @Nullable Looper myLooper() {
        return sThreadLocal.get();      // 还是通过 sThreadLocal.get()方法获取当前线程绑定的 Looper 对象
    }

MessageQueue

// Looper 构造函数中创建了 mQueue,即 MessageQueue
private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);  // 创建 MessageQueue 对象
    mThread = Thread.currentThread();        // 记录当前线程
}
public static void loop() {
        final Looper me = myLooper();             // 获取当前线程绑定的 Looper 对象
        if (me == null) {
            ... ...
        }
        final MessageQueue queue = me.mQueue;     // 获取 Looper 对象中的消息队列

变量 me 是通过静态方法 myLooper() 获得的当前线程所绑定的 Looper,me.mQueue 就是当前线程所关联的消息队列。

for()

for (;;) {     // 进入loop的主循环方法

我们发现for循环没有设置循环终止的条件,所以这个for循环是个死循环。

Message

Message msg = queue.next(); // might block

我们通过消息队列 MessageQueue 的 next 方法从消息队列中取出一条消息,如果此时消息队列中有 Message,那么 next 方法会立即返回该 Message,如果此时消息队列中没有 Message,那么 next 方法就会阻塞式地等待获取 Message。

dispatchMessage()

/*package*/ Handler target;
try {
    msg.target.dispatchMessage(msg);
    end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
    if (traceTag != 0) {
        Trace.traceEnd(traceTag);
    }
}

msg 的 target 属性是 Handler,该代码的意思是让 Message 所关联的 Handler 通过 dispatchMessage 方法让 Handler 处理该 Message ,关于 Handler 的 dispatchMessage 方法将会在下面详细介绍。

recycleUnchecked()

msg.recycleUnchecked();    // 分发后的 Message 回收到消息池,以便重复利用

小结

loop()进入循环模式,不断重复下面的操作,直到没有消息时退出循环:

1、读取 MessageQueue 的下一条 Message;
2、把 Message 分发给相应的 target;
3、再把分发后的 Message 回收到消息池,以便重复利用。

quit()

public void quit() {
        mQueue.quit(false);          // 消息移除
    }

    public void quitSafely() {
        mQueue.quit(true);           // 安全消息移除
    }

Looper.quit() 方法的实现最终调用的是 MessageQueue.quit() 方法。

MessageQueue.quit()

void quit(boolean safe) {
        if (!mQuitAllowed) {    当 mQuitAllowed 为 false,表示不运行退出,强行调用 quit() 会抛出异常
            throw new IllegalStateException("Main thread not allowed to quit.");
        }

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;

            if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked();
            }

            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }
消息退出的方式:

当 safe = true 时,只移除尚未触发的所有消息,对于正在触发的消息并不移除
当 safe = flase 时,移除所有的消息

Handler

构造函数

无参构造

public Handler() {
        this(null, false);
    }

    public Handler(Callback callback) {
        this(callback, false);
    }

    public Handler(boolean async) {
        this(null, async);
    }
    
    public Handler(Callback callback, boolean async) {
        // 匿名类、内部类或本地类都必须申明为static,否则会警告可能出现内存泄露
        if (FIND_POTENTIAL_LEAKS) {     // 默认为 false
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        // 必须先执行 Looper.prepare(),才能获取 Looper 对象,否则为null
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;     // 回调方法
        mAsynchronous = async;    // 设置消息是否为异步处理方式
    }

对于 Handler 的无参构造方法,默认采用当前线程 TLS 中的 Looper 对象,并且 callback 回调方法为 null,且消息为同步处理方式。只要执行的 Looper.prepare() 方法,那么便可以获取有效的 Looper 对象。

有参构造

public Handler(Looper looper) {
        this(looper, null, false);
    }
    
    public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
    }
    
    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

Handler 类在构造方法中,可指定 Looper,Callback 回调方法以及消息的处理方式(同步或异步),对于无参的 handler,默认是当前线程的 Looper。

dispatchMessage()

在 Looper.loop() 中,当发现有消息时,调用消息的目标 handler,执行 dispatchMessage() 方法来分发消息。

/**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            // 当 Message 存在回调方法,回调 msg.callback.run() 方法
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                // 当 Handler 存在 Callback 成员变量时,回调方法 handleMessage()
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            // Handler 自身的回调方法 handleMessage()
            handleMessage(msg);
        }
    }

我们需要重点分析下这个函数:

首先会判断 msg.callback 存不存在,msg.callback 是 Runnable 类型,如果 msg.callback 存在,那么说明该 Message 是通过执行 Handler 的 post() 系列方法将 Message 放入到消息队列中的,这种情况下会执行 handleCallback(msg)。

handleCallback

源码如下:

private static void handleCallback(Message message) {
        message.callback.run();
    }

这样我们就清楚地看到我们执行了 msg.callback 的 run 方法,也就是执行了 post() 所传递的 Runnable 对象的 run 方法。

mCallback

如果我们不是通过 post() 系列方法将 Message 放入到消息队列中的,那么 msg.callback 就是 null ,代码继续往下执行。

接着我们会判断 Handler 的成员字段 mCallback 存不存在。mCallback 是 Hanlder.Callback 类型的,我们在上面提到过,在 Handler 的构造函数中我们可以传递 Hanlder.Callback 类型的对象,该对象需要实现 handleMessage 方法,如果我们在构造函数中传递了该 Callback 对象,那么我们就会让 Callback 的 handleMessage 方法来处理 Message。

final Callback mCallback;
    
    public interface Callback {
        /**
         * @param msg A {@link android.os.Message Message} object
         * @return True if no further handling is desired
         */
        public boolean handleMessage(Message msg);
    }

如果我们在构造函数中没有传入 Callback 类型的对象,那么 mCallback 就为 null ,那么我们会调用 Handler 自身的 hanldeMessage 方法,该方法默认是个空方法,我们需要自己重写实现该方法。

/**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {      // 空函数
    }

综上所述,我们可以看到 Handler 提供了三种途径处理 Message ,而且处理有前后优先级之分:首先尝试让 post() 中传递的 Runnable 执行,其次尝试让 Handler 构造函数中传入的 Callback 的 handleMessage 方法处理,最后才是让 Handler 自身的 handleMessage 方法处理Message。

Callback

Callback 是 Handle r中的内部接口,需要实现其内部的 handleMessage 方法,Callback 代码如下:

public interface Callback {
        public boolean handleMessage(Message msg);
    }

Handler.Callback 是用来处理 Message 的一种手段,如果没有传递该参数,那么就应该重写 Handler 的 handleMessage 方法,也就是说为了使得 Handler 能够处理 Message ,有两种办法:

  1. 向 Hanlder 的构造函数传入一个 Handler.Callback 对象,并实现 Handler.Callback 的 handleMessage 方法
  2. 无需向 Hanlder 的构造函数传入 Handler.Callback 对象,但是需要重写 Handler 本身的 handleMessage 方法

也就是说无论哪种方式,我们都得通过某种方式实现 handleMessage 方法,这点与 Java 中对 Thread 的设计有异曲同工之处。

在Java中,如果我们想使用多线程,有两种办法:

1. 向 Thread 的构造函数传入一个 Runnable 对象,并实现 Runnable 的 run 方法

2. 无需向 Thread 的构造函数传入 Runnable 对象,但是要重写 Thread 本身的 run 方法 

所以只要用过多线程 Thread,应该就对 Hanlder 这种需要实现 handleMessage 的两种方式了然于心了。

在之前分析 Handler(用法篇)的时候我们讲到过两种重要的方法:sendMessage() 和 post(),我们从源码角度进行进一步分析!

sendMessage

我们看下 sendMessage() 源码处理流程:

public final boolean sendMessage(Message msg) {
    return sendMessageDelayed(msg, 0);
}

sendMessageDelayed

public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);     // 最终调 sendMessageAtTime()
    }

通过以上代码可以看书:sendMessage() 调用了 sendMessageDelayed() ,sendMessageDelayed() 又调用了 sendMessageAtTime()。

Handler 中还有 sendEmptyMessage() 方法:

public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 0);
    }
    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);     // 最终还是要调 sendMessageAtTime()
    }

由此可见所有的 sendMessage 方法和 sendEmptyMessage 最终都调用了 sendMessageAtTime 方法。

post

我们看下 post() 源码处理流程:

public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

可以看到内部调用了 getPostMessage 方法,该方法传入一个 Runnable 对象,得到一个 Message 对象。

getPostMessage

getPostMessage() 的源码如下:

private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

通过上面的代码我们可以看到在 getPostMessage 方法中,我们创建了一个 Message 对象,并将传入的 Runnable 对象赋值给 Message 的 callback 成员字段,然后返回该 Message ,然后在 post 方法中该携带有 Runnable 信息的 Message 传入到 sendMessageDelayed 方法中。由此我们可以看到所有的 post 方法内部都需要借助 sendMessage 方法来实现,所以 post() 与 sendMessage() 并不是对立关系,而是 post() 依赖 sendMessage() ,所以 post() 方法可以通过 sendMessage() 方法向消息队列中传入消息,只不过通过 post() 方法向消息队列中传入的消息都携带有 Runnable 对象(Message.callback)。

sendMessageAtTime

通过分别分析 sendEmptyMessage()、post() 方法与 sendMessage() 方法之间的关系,我们可以看到在 Handler 中所有可以直接或间接向消息队列发送 Message 的方法最终都调用了 sendMessageAtTime 方法,该方法的源码如下:

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

enqueueMessage

我们发现 sendMessageAtTime() 方法内部调用了 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;     // 将 Message 的 target 绑定为当前的 Handler
// 变量 queue 表示的是 Handler 所绑定的消息队列 MessageQueue ,通过调用 queue.enqueueMessage(msg, uptimeMillis) 将 Message 放入到消息队列中。
queue.enqueueMessage(msg, uptimeMillis);

还记得我们之前在分析 Looper 的时候,最终提到的 dispatchMessage() 吗?我们回忆一下:

try {
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }

MessageQueue

每个线程内部都维护了一个消息队列 —— MessageQueue。消息队列 MessageQueue,顾名思义,就是存放消息的队列。那队列中存储的消息是什么呢?

假设我们在UI界面上单击了某个按钮,而此时程序又恰好收到了某个广播事件,那我们如何处理这两件事呢?因为一个线程在某一时刻只能处理一件事情,不能同时处理多件事情,所以我们不能同时处理按钮的单击事件和广播事件,我们只能挨个对其进行处理,只要挨个处理就要有处理的先后顺序。

为此Android把UI界面上单击按钮的事件封装成了一个 Message ,将其放入到 MessageQueue 里面去,即将单击按钮事件的 Message 入栈到消息队列中,然后再将广播事件的封装成以 Message ,也将其入栈到消息队列中。

也就是说一个 Message 对象表示的是线程需要处理的一件事情,消息队列就是一堆需要处理的 Message 的池。线程 Thread 会依次取出消息队列中的消息,依次对其进行处理。

MessageQueue 中有两个比较重要的方法,一个是 enqueueMessage 方法,一个是 next 方法。enqueueMessage 方法用于将一个 Messag e放入到消息队列 MessageQueue 中,next 方法是从消息队列 MessageQueue 中阻塞式地取出一个 Message。在 Android 中,消息队列负责管理着顶级程序对象(Activity、BroadcastReceiver等)以及由其创建的所有窗口。

创建MessageQueue

MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        // 通过 native 方法初始化消息队列,其中 mPtr 是供 native 代码使用
        mPtr = nativeInit();
    }

next()

Message next() {
        final long ptr = mPtr;
        if (ptr == 0) {     // 当消息循环已经退出,则直接返回
            return null;
        }

        // 循环迭代的首次为 -1
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            // 阻塞操作,当等待 nextPollTimeoutMillis 时长,或者消息队列被唤醒,都会返回
            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;
                if (msg != null && msg.target == null) {
                    // 当消息 Handler 为空时,查询 MessageQueue 中的下一条异步消息 msg,则退出循环
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // 当异步消息触发时间大于当前时间,则设置下一次轮询的超时时长
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // 获取一条消息,并返回
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        // 设置消息的使用状态,即 flags |= FLAG_IN_USE
                        msg.markInUse();
                        // 成功地获取 MessageQueue 中的下一条即将要执行的消息
                        return msg;
                    }
                } else {
                    // 没有消息
                    nextPollTimeoutMillis = -1;
                }

                // 消息正在退出,返回null
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // 当消息队列为空,或者是消息队列的第一个消息时
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                // 没有 idle handlers 需要运行,则循环并等待
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // 只有第一次循环时,会运行 idle handlers,执行完成后,重置 pendingIdleHandlerCount 为 0
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // 去掉 handler 的引用

                boolean keep = false;
                try {
                    keep = idler.queueIdle();   // idle 时执行的方法
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // 重置 idle handler 个数为 0,以保证不会再次重复运行
            pendingIdleHandlerCount = 0;

            // 当调用一个空闲 handler 时,一个新 message 能够被分发,因此无需等待可以直接查询 pending message
            nextPollTimeoutMillis = 0;
        }
    }

nativePollOnce 是阻塞操作,其中 nextPollTimeoutMillis 代表下一个消息到来前,还需要等待的时长;当 nextPollTimeoutMillis = -1 时,表示消息队列中无消息,会一直等待下去。

当处于空闲时,往往会执行 IdleHandler 中的方法。当 nativePollOnce() 返回后,next() 从 mMessages 中提取一个消息。

enqueueMessage()

boolean enqueueMessage(Message msg, long when) {
        // 每一个普通 Message 必须有一个 target
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            // 正在退出时,回收 msg,加入到消息池
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // p 为 null (代表MessageQueue没有消息) 或者 msg 的触发时间是队列中最早的,则进入该该分支
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;   // 当阻塞时需要唤醒
            } else {
                // 将消息按时间顺序插入到 MessageQueue。一般地,不需要唤醒事件队列,除非
                // 消息队头存在 barrier,并且同时 Message 是队列中最早的异步消息
                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;
            }

            // 消息没有退出,我们认为此时 mPtr != 0
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

MessageQueue 是按照 Message 触发时间的先后顺序排列的,队头的消息是将要最早触发的消息。当有消息需要加入消息队列时,会从队列头开始遍历,直到找到消息应该插入的合适位置,以保证所有消息的时间顺序。

removeMessages()

void removeMessages(Handler h, int what, Object object) {
        if (h == null) {
            return;
        }

        synchronized (this) {
            Message p = mMessages;

            // 从消息队列的头部开始,移除所有符合条件的消息
            while (p != null && p.target == h && p.what == what
                   && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycleUnchecked();
                p = n;
            }

            // 移除剩余的符合要求的消息
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    if (n.target == h && n.what == what
                        && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    }

这个移除消息的方法,采用了两个 while 循环,第一个循环是从队头开始,移除符合条件的消息,第二个循环是从头部移除完连续的满足条件的消息之后,再从队列后面继续查询是否有满足条件的消息需要被移除。

总结

最后用一张图,来表示整个消息机制:

Android 8.1 源码_机制篇 -- 全面解析 Handler 机制(原理篇)

图解:

:sparkles: Handler通过sendMessage()发送Message到MessageQueue队列;

:sparkles: Looper通过loop(),不断提取出达到触发条件的Message,并将Message交给target来处理;

:sparkles: 经过dispatchMessage()后,交回给Handler的handleMessage()来进行相应地处理。

:sparkles: 将Message加入MessageQueue时,处往管道写入字符,可以会唤醒loop线程;如果MessageQueue中没有Message,并处于Idle状态,则会执行IdelHandler接口中的方法,往往用于做一些清理性地工作。

参考Blog

01. https://blog.csdn.net/iisprin...

02. http://gityuan.com/2015/12/26...


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

伏牛传

伏牛传

张天一 / 机械工业出版社 / 2016-5 / 39.00元

编辑推荐: 伏牛堂创始人张天一独家揭秘 社群品牌运营背后的规律和逻辑 90后创业者张天一白手起家,在伏牛堂创立一年之际,已是京城大众点评口碑最佳湖南牛肉粉店、获得四轮数千万投资,他是如何做到的? 餐饮品牌伏牛堂如何建设20万人的青年人生活社群 “霸蛮社”,并快速成为知名品牌? 内容推荐: 《伏牛传:一个社群品牌的内部运营笔记》是一本餐饮社群品牌的内部运营笔记,90后创......一起来看看 《伏牛传》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

html转js在线工具
html转js在线工具

html转js在线工具