android中处理一些费时的操作需要单独启动一个子线程去处理。子线程处理完毕将结果通知给UI主线程更新UI界面。 子线程与UI主线程的通信在android中使用了消息机制来完成,那么是怎么完成的呢?这就和handler机制的原理(android中线程间通信的原理,而不是进程间通信), 简而言之,就是需要两样古老的东西,消息队列、轮询。也就是说,主线程起来以后有一个消息队列,同时和该队列配对的有一个轮询, 而子线程有这个消息队列的引用,那这样,子线程处理完以后就会向主线程的消息队列发消息,主线程轮询自己的队列,发现有未处理的消息就进行处理。 这就是handler的机制。

下面介绍Handler,Message,MessageQueue,Looper的关系:

looper对象拥有message queue,并且负责从message queue中取出消息给handler来处理。同时handler又负责发送message给looper,由looper把message添加到message queue尾部。 handler和looper是来联系在一起的。多个message可以指向同一个handler,多个handler也可以指向同一个looper。

Handler

消息的处理者,handler负责将需要传递的信息封装成Message,通过调用handler对象的obtainMessage()来实现。将消息传递给Looper, 这是通过handler对象的sendMessage()来实现的。继而由Looper将Message放入MessageQueue中。当Looper对象看到MessageQueue中含有Message, 就将其分发出去。该handler对象收到该消息后,调用相应的handler对象的handleMessage()方法对其进行处理。

Handler一些特点:handler可以分发Message对象和Runnable对象到主线程中,每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程), 它有两个作用: (1)安排消息或Runnable在某个主线程中某个地方执行。(2)安排一个动作在不同的线程中执行。

Message

消息对象,Message Queue中的存放的对象。一个Message Queue中包含多个Message。Message实例对象的取得, 通常使用Message类里的静态方法obtain(),该方法有多个重载版本可供选择;它的创建并不一定是直接创建一个新的实例, 而是先从Message Pool(消息池)中看有没有可用的Message实例,存在则直接取出返回这个实例。如果Message Pool中没有可用的Message实例, 则才用给定的参数创建一个Message对象。调用removeMessages()时,将Message从Message Queue中删除,同时放入到Message Pool中。 除了上面这种方式,也可以通过Handler对象的obtainMessage()获取一个Message实例。

MessageQueue

消息队列,存放消息的地方。每一个线程最多只可以拥有一个MessageQueue数据结构。创建一个线程的时候,并不会自动创建其MessageQueue。 通常使用一个Looper对象对该线程的MessageQueue进行管理。主线程创建时,会创建一个默认的Looper对象,而Looper对象的创建, 将自动创建一个Message Queue。其他非主线程,不会自动创建Looper,要需要的时候,通过调用Looper的prepare函数来实现。

Looper

Looper是MessageQueue的管理者。每一个MessageQueue都不能脱离Looper而存在,Looper对象的创建是通过prepare函数来实现的。 同时每一个Looper对象和一个线程关联。通过调用Looper.myLooper()可以获得当前线程的Looper对象 创建一个Looper对象时, 会同时创建一个MessageQueue对象。除了主线程有默认的Looper,其他线程默认是没有MessageQueue对象的,所以,不能接受Message。 如需要接受,自己定义一个Looper对象(通过prepare函数),这样该线程就有了自己的Looper对象和MessageQueue数据结构了,而且一个线程只能有一个looper。 调用完prepare以后,此线程就成为了所谓的LooperThread,若在当前LooperThread中创建Handler对象,那么此Handler会自动关联到当前线程的looper对象,也就是拥有looper的引用。 Looper从MessageQueue中取出Message然后,交由Handler的handleMessage进行处理。处理完成后,调用Message.recycle()将其放入Message Pool中。

源码解析

handler其构造函数:

    
    /**
     * Default constructor associates this handler with the {@link Looper} for the
     * current thread.
     *
     * If this thread does not have a looper, this handler won't be able to receive messages
     * so an exception is thrown.
     */
    public Handler() {
        this(null, false);
    }
    /**
     * Constructor associates this handler with the {@link Looper} for the
     * current thread and takes a callback interface in which you can handle
     * messages.
     *
     * If this thread does not have a looper, this handler won't be able to receive messages
     * so an exception is thrown.
     *
     * @param callback The callback interface in which to handle messages, or null.
     */
    public Handler(Callback callback) {
        this(callback, false);
    }
    /**
     * Use the provided {@link Looper} instead of the default one.
     *
     * @param looper The looper, must not be null.
     */
    public Handler(Looper looper) {
        this(looper, null, false);
    }
    /**
     * Use the provided {@link Looper} instead of the default one and take a callback
     * interface in which to handle messages.
     *
     * @param looper The looper, must not be null.
     * @param callback The callback interface in which to handle messages, or null.
     */
    public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
    }
    /**
     * Use the {@link Looper} for the current thread
     * and set whether the handler should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
     *
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     *
     * @hide
     */
    public Handler(boolean async) {
        this(null, async);
    }
    /**
     * Use the {@link Looper} for the current thread with the specified callback interface
     * and set whether the handler should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
     *
     * @param callback The callback interface in which to handle messages, or null.
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     *
     * @hide
     */
    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;
    }
    /**
     * Use the provided {@link Looper} instead of the default one and take a callback
     * interface in which to handle messages.  Also set whether the handler
     * should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
     *
     * @param looper The looper, must not be null.
     * @param callback The callback interface in which to handle messages, or null.
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     *
     * @hide
     */
    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    

构造方法中无参构造和没有传递looper的构造最终调用了public Handler(Callback callback, boolean async); 在这个方法中获得当前线程的looper,再使用这个looper获得looper上的message queue。

而如果构造中传递了looper,则调用 public Handler(Looper looper, Callback callback, boolean async), 用传递进来的looper代替默认的looper,然后再同样的初始化mQueue,mCallback,mAsynchronous。

先看mLooper = Looper.myLooper();这一句发生了什么:

   
public static Looper myLooper() {
    return sThreadLocal.get();
}
    

可以看到,该方法返回一个sThreadLocal对象中保存的Looper。如果尚未在当前线程上运行过Looper.prepare()的话,myLooper会返回null。 接下来看看Looper.prepare()的实现:

   
/** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    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));
    }
     

可以看到该方法只是简单地新建了一个Looper对象,并将其保存在sThreadLocal中。在注释中说明了prepare()要在loop()之前调用,最后 调用quit()。接下来看一下Looper的构造函数。

  
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
     

调用完Looper.prepare()后,需调用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();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;
        // 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 (;;) {
            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
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
            msg.target.dispatchMessage(msg);
            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();
        }
    }
         

在loop()主要干了四件事:

1.调用Looper me = myLooper()取出looper对象。

2.调用MessageQueue queue = me.mQueue; 取出looper绑定的message queue。

3.死循环调用Message msg = queue.next();在message queue中取数据,若msg为null就不执行下面的分发,跳出死循环。 这里为什么敢直接跳出循环?因为上一行的queue.next()里也是一个循环,这个循环实现很巧妙,只有遇到message时才取出,否则阻塞。 一旦queue.next()里的循环阻塞了,外面的for循环也阻塞了,避免了空循环浪费资源。queue.next()里的for循环也不是一直做空循环的, 它会根据message里的when字段(postDelay设置的延迟)来计算时间,到时间了才会开始取,其他时间都是阻塞状态。

4.在上面的循环中若msg不为null,调用msg.target.dispatchMessage(msg); 分发message到指定的target handler。

  
  /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    

分发之后就执行了mCallback中的回调,这个回调就是我们自己覆写的方法public void handleMessage(Message msg)。

从上面代码也可以看出,轮询器在for (;;){}死循环代码块中不断的执行,通过queue.next();从MessageQueue中取出一个Message, 当msg不为空时,执行msg.target.dispatchMessage(msg);(实际上最终是调用到了Handler的dispatchMessage方法去拦截消息)

在Message中的源码中,target就是当前线程的Handler对象,msg的成员变量target是在发送消息的时候设置好的,一般就通过哪个Handler 来发送消息,就通过哪个Handler来处理消息。

接下来看一下Message类:

  
public final class Message implements Parcelable {
    public int what;
    public int arg1;
    public int arg2;
    public Object obj;
    ...
    /*package*/ int flags;
    /*package*/ long when;
    /*package*/ Bundle data;
    /*package*/ Handler target;
    /*package*/ Runnable callback;
    /*package*/ Message next;
    private static final Object sPoolSync = new Object();
    private static Message sPool;
    private static int sPoolSize = 0;
}
    

Message中有一个静态类型的Message对象,叫做sPool,同时还有一个叫做next的Message对象,这个应该是指向队列中下一个message的引用。 当我们调用Message.obtain()时,返回了一个Message对象。Message对象使用完毕后,调用recycle()方法将其回收。其中obtain方法的代码如下所示:

 
        /**
         * Return a new Message instance from the global pool. Allows us to
         * avoid allocating new objects in many cases.
         */
        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();
        }
            

可以看到,obtain方法被调用时,首先检测sPool对象是否为空,若不为空将其当做新的message对象返回,并指向message对象的next属性, sPoolSize自减。可以看出message对象通过next属性串成了一个链表,sPool为“头指针”。再来看看recycle方法的实现。

 
    /**
     * Return a Message instance to the global pool.
     * <p>
     * You MUST NOT touch the Message after calling this function because it has
     * effectively been freed.  It is an error to recycle a message that is currently
     * enqueued or that is in the process of being delivered to a Handler.
     * </p>
     */
    public void recycle() {
        if (isInUse()) {
            if (gCheckRecycle) {
                throw new IllegalStateException("This message cannot be recycled because it "
                        + "is still in use.");
            }
            return;
        }
        recycleUnchecked();
    }
    /**
     * Recycles a Message that may be in-use.
     * Used internally by the MessageQueue and Looper when disposing of queued Messages.
     */
    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;
        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
    

如果message对象不是处于正在被使用的状态,则会被回收。其属性全部恢复到原始状态后,放在了链表的头部。sPool对象“指向”它,sPoolSize自增。 可以看出,通过obtain和recycle方法可以重用message对象。通过操作next、sPoolSync、sPool、sPoolSize这四个属性,实现了一个类似栈的对象池。

下面看看msg对象是如何放到消息队列里面的,通常来说,我们通过Handler的sendMessage(msg)方法来发送消息,其源码如下所示:

 
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;
    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);
}
...
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}
    

可知sendMessage最终会调用queue.enqueueMessage(msg, uptimeMillis)将msg对象保存至message queue中,uptimeMillis表示msg执行回调的时刻。 我们来看一下MessageQueue类的enqueueMessage方法:

 
boolean enqueueMessage(Message msg, long when) {
    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) {
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w("MessageQueue", e.getMessage(), e);
            msg.recycle();
            return false;
        }
        // 1.设置当前msg的状态
        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        // 2.检测当前头指针是否为空(队列为空)或者没有设置when 或者设置的when比头指针的when要前
        if (p == null || when == 0 || when < p.when) {
            // 3. 插入队列头部,并且唤醒线程处理msg
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            //4. 几种情况要唤醒线程处理消息:1)队列是堵塞的 2)barrier,头部结点无target 3)当前msg是堵塞的
            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;
                }
            }
            // 5. 将当前msg插入第一个比其when值大的结点前。
            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;
}
    

结合注释,我们可以了解到msg push到queue中时,queue的状态的变化和处理队列的逻辑。 前文中Looper对象的loop方法中:

 
for (;;) {
    ...
    Message msg = queue.next(); // 3. 堵塞式在message queue中取数据
    if (msg == null) {
        // No message indicates that the message queue is quitting.
        return;
    }
    ...
    msg.target.dispatchMessage(msg); 4. 分发message到指定的target handler
    ...
}
    

可以看出,message queue的next方法被调用时,可能会发生堵塞。我们来看一看message queue的next方法:

 
Message next() {
    // 1. 判断当前loop是否已经使用过,下文会解释这个mPtr
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }
    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    // 2. 进入死循环,直到获取到合法的msg对象为止。
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands(); // 这个是什么?
        }
        // 3. 进入等待,nextPollTimeoutMillis为等待超时值
        nativePollOnce(ptr, nextPollTimeoutMillis);
        synchronized (this) {
            // 4. 获取下一个msg
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                // 当前节点为barrier,所以要找到第一个asynchronous节点
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    // 当前队列里最早的节点比当前时间还要晚,所以要进入堵塞状态,超时值为nextPollTimeoutMillis
                    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;
                    if (false) Log.v("MessageQueue", "Returning message: " + msg);
                    return msg;
                }
            } else {
                // 头结点指向null
                nextPollTimeoutMillis = -1;
            }
            // Process the quit message now that all pending messages have been handled.
            if (mQuitting) {
                dispose();
                return null;
            }
            // 5. 如果当前状态为idle(就绪),则进入idle handle的代码块
            //    进入idle的情况有:队列为空;队列头元素blocking;
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // 6. 本轮唤醒(next被调用)时没处理任何东西,故再次进入等待。
                mBlocked = true;
                continue;
            }
            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }
        // 在一次next调用中,这个代码块只会执行一次
        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 {
                // 如果返回true,则idler被保留,下次next的idle时会被调用。
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf("MessageQueue", "IdleHandler threw exception", t);
            }
            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }
        // Reset the idle handler count to 0 so we do not run them again.
        pendingIdleHandlerCount = 0;
        // While calling an idle handler, a new message could have been delivered
        // so go back and look again for a pending message without waiting.
        nextPollTimeoutMillis = 0;
    }
}
    

代码执行流程见注释。其中IdleHandler是一个接口:

 
public static interface IdleHandler {
    boolean queueIdle();
}
    

IdleHandler提供了一个在MessageQueue进入idle时的一个hook point。更多时与barrier机制一起使用,使message queue遇到barrier时产生一个回调。

总结

前面涉及到的几个主要的类Handler、Looper、MessageQueue和Message的关系如下所述:

1.Handler负责将Looper绑定到线程,初始化Looper和提供对外API。 2.Looper负责消息循环和操作MessageQueue对象。 3.MessageQueue实现了一个堵塞队列。 4.Message是一次业务中所有参数的载体。

参考原文:

Android应用程序消息处理机制

Handler源码解析 (Java层)

Handler源码解析 (Native层)