异步任务之 Handler 源码初解

说起 Handler,都离不开 Message、MessageQueue、Looper 和 Handler 这四大件,我们知道需要重写 Handler 的 handleMessage 方法来处理 Message,Looper 让 MessageQueue 循环起来传递 Message,但是其中的过程又是怎么操作的呢?来从源码看一下吧。本文篇幅可能会很长,预警预警!

Message

既然是消息传递,那就先看一下 Message,总所周知,Message 对象是携带数据的,我们如何得到 Message 对象呢?

    // Message 构造方法
    public Message() {
    }
    // Message 静态方法
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
    public static Message obtain(Message orig) {
        Message m = obtain();
        m.what = orig.what;
        m.arg1 = orig.arg1;
        m.arg2 = orig.arg2;
        m.obj = orig.obj;
        m.replyTo = orig.replyTo;
        m.sendingUid = orig.sendingUid;
        if (orig.data != null) {
            m.data = new Bundle(orig.data);
        }
        m.target = orig.target;
        m.callback = orig.callback;

        return m;
    }
    public static Message obtain(Handler h) {
        Message m = obtain();
        m.target = h;

        return m;
    }
    public static Message obtain(Handler h, Runnable callback) {
        Message m = obtain();
        m.target = h;
        m.callback = callback;

        return m;
    }
        public static Message obtain(Handler h, int what) {
        Message m = obtain();
        m.target = h;
        m.what = what;

        return m;
    }
    public static Message obtain(Handler h, int what, Object obj) {
        Message m = obtain();
        m.target = h;
        m.what = what;
        m.obj = obj;

        return m;
    }
    public static Message obtain(Handler h, int what, int arg1, int arg2) {
        Message m = obtain();
        m.target = h;
        m.what = what;
        m.arg1 = arg1;
        m.arg2 = arg2;

        return m;
    }
    public static Message obtain(Handler h, int what, 
            int arg1, int arg2, Object obj) {
        Message m = obtain();
        m.target = h;
        m.what = what;
        m.arg1 = arg1;
        m.arg2 = arg2;
        m.obj = obj;

        return m;
    }
    // Handler 对象的 obtainMessage 方法
    public final Message obtainMessage()
    {
        return Message.obtain(this);
    }
    public final Message obtainMessage(int what)
    {
        return Message.obtain(this, what);
    }
    public final Message obtainMessage(int what, int arg1, int arg2)
    {
        return Message.obtain(this, what, arg1, arg2);
    }
    public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
    {
        return Message.obtain(this, what, arg1, arg2, obj);
    }
    public final Message obtainMessage(int what, Object obj)
    {
        return Message.obtain(this, what, obj);
    }

除了构造方法之外,其余的方法都会调用 obtain 方法,详细看一下这个方法:

    private static final Object sPoolSync = new Object();
    private static Message sPool;

    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {    // 如果消息不为空,则复用该消息,而不是新建对象
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // 复用消息之前,需要先重置其标志位
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

可以看到,如果 sPool 不为空,则直接返回;如果为空,则新建一个 Message 对象返回,所以 Android 建议我们使用 obtain 方法获取 Message,这样比直接新建 Message 对象要节省内存一些。

创建好 Message 之后,我们再给这个空的 Message 设置所要携带的数据和属性:

    public int what;    // Message 标识
    public int arg1;    // Message 传递整形数据
    public int arg2;
    public Object obj;  // Message 传递 Object 类型数据
    // Message 传递 Bundle 对象
    public void setData(Bundle data) {
        this.data = data;
    }
    // Message 的发送时间

这样,一个满载数据的 Message 就创建出来了。当然 Message 还有其他属性和方法,这个在后面会讲到。

一个消息创建出来了,我们需要将它发送出去,谁来发送,发送到哪里,就是 Handler 的事儿了

Handler

Handler 对象的创建有以下方法:

    final Looper mLooper;
    final MessageQueue mQueue;
    final Callback mCallback;
    final boolean mAsynchronous;

    public Handler() {
        this(null, false);
    }
    public Handler(Callback callback) {
        this(callback, false);
    }
    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;
    }
    public Handler(boolean async) {
        this(null, async);
    }
    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            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());
            }
        }

        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 对象的同时,也为该 Handler 初始化了一个 Looper 对象和一个 MessageQueue 对象(关于 Looper 和 MessageQueue 在下文会讲解)。

然后看一下 Handler 对象发送消息的方法,Handler 提供了 sendXXX 和 postXXX 几种方法:

    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
    public final boolean sendMessageAtFrontOfQueue(Message msg) {
        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, 0);
    }
    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);
    }
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    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 sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
    }
    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    public final boolean postAtFrontOfQueue(Runnable r)
    {
        return sendMessageAtFrontOfQueue(getPostMessage(r));
    }
    public final boolean postDelayed(Runnable r, long delayMillis)
    {
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }
    public final boolean postAtTime(Runnable r, long uptimeMillis)
    {
        return sendMessageAtTime(getPostMessage(r), uptimeMillis);
    }

这些方法最终都会调用到 enqueueMessage 方法:

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

在这个方法中会先为 Message 设置一个 target(设置为当前 Handler 对象),然后再设置消息是否同步,最后调用 MessageQueue 的 enqueneMessage 方法将消息推入消息队列当中。

关于异步消息,可以看以下博文:

到了这里,我们将一个满载着数据的 Message 对象传送到了 MessageQueue 当中,接下来呢?看一下 MessageQueue 是如何工作的。

MessageQueue

来看 MessageQueue 的 enqueneMessage 方法:

    boolean enqueueMessage(Message msg, long when) {
    // 判断传入的 Message 是否设置 target
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        // 判断传入的 Message 是否已经使用过
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
        // 判断消息队列是否已经退出,如果已经退出,抛出异常,不能再给其发送消息
            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) {
                // 消息队列当中没有消息
                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;
            }

            // 唤醒主线程
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

Message 已经传入至 MessageQueue 当中,但是并没有循环起来啊。其实,MessageQueue 只是一个循环队列,队列是重点,循环是由 Looper 去操作的。来看 Looper 代码:

Looper

看 Looper 的 loop() 方法:

    public static void loop() {
        final Looper me = myLooper();  // 获取到当前线程绑定的 Looper。
        // 如果 Looper 为空,则抛出异常,一般发生在子线程创建 Handler 当中,因为 UI 线程会自动创建 Looper
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        // 拿到 Looper 维护的 MessageQueue
        final MessageQueue queue = me.mQueue;

        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        // 进入到一个死循环当中
        for (;;) {
            Message msg = queue.next(); // 从消息队列当中获取消息
            if (msg == null) {
                return;
            }

            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long traceTag = me.mTraceTag;
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            try {
            // 【重点】分发消息,Handler 对象的 enqueueMessage 执行时,为 Message 设置 target 为当前对象
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }

            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();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            // 回收消息
            msg.recycleUnchecked();
        }
    }

来看 Handler 的 dispatchMessage 方法:

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

如果我们当初创建 Handler 时候传入了 Callback 对象,则 Message 交由 Callback 对象的 handleMessage 方法处理,如果当初没有传入,则由 Handler 的 handleMessage 处理,我们创建 Handler 对象时需要重写 handleMessage 方法,然后该怎么干就怎么干喽。至此,消息循环完毕。

总结

  1. 我们在创建 Handler 对象时,会和当前线程所绑定的 Looper 一起绑定。
  2. UI 线程在创建之初即随之创建了 Looper,而我们自己创建的线程不会自动创建,需要调用 Looper.prepare() 来获取 Looper。
  3. Looper 内部维护了一个 MessageQueue。
  4. Looper 会循环的从 MessageQueue 当中拿消息,UI 线程默认启动 Looper,而子线程需要调用 Looper.loop() 去循环的拿消息。
  5. 调用 Handler 对象的 sendXXXpostXXX 方法将消息压入到 MessageQueue 当中待 Looper 去拿取。
  6. Looper 拿到消息,分发交由 Handler 或者 Handler.Callback 处理。
Copyright© 2020-2022 li-xyz 冀ICP备2022001112号-1