之前写过一篇文章,概述了Android应用程序消息处理机制。本文在此文基础上,在源码级别上展开进行概述

简单用例

Handler的使用方法如下所示:

Handler myHandler = new Handler() {            public void handleMessage(Message msg) {                  switch (msg.what) {                       ...                 }          }        };class myThread implements Runnable {             public void run() {                 while (!Thread.currentThread().isInterrupted()) {                                               Message message = Message.obtain();                       message.what = TestHandler.GUIUPDATEIDENTIFIER;                    TestHandler.this.myHandler.sendMessage(message);                       message.recycle();                    try {                            Thread.sleep(100);                        } catch (InterruptedException e) {                            Thread.currentThread().interrupt();                       }                  }             }        }

或者:

mHandler=new Handler();mHandler.post(new Runnable(){    void run(){       ...     }});

又或者:

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();    }}

源码解析

首先看其构造函数:

new Handler()...public Handler() {    this(null, false);}...public Handler(Looper looper, Callback callback) {    this(looper, callback, false);}...public Handler(Callback callback, boolean async) {    if (FIND_POTENTIAL_LEAKS) { // 默认为false,若为true则会检测当前handler是否是静态类        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());        }    }    // 1. 获得当前线程的looper    mLooper = Looper.myLooper();    if (mLooper == null) {        throw new RuntimeException(            "Can't create handler inside thread that has not called Looper.prepare()");    }    //2. 获得looper上的message queue    mQueue = mLooper.mQueue;    mCallback = callback;    mAsynchronous = async;}

由此引入了两个关键对象Looper和MessageQueue。

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

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

可以看到,该方法返回一个sThreadLocal对象中保存的Looper。关于ThreadLocal类,请参考这里,本文不展开。
如果尚未在当前线程上运行过Looper.prepare()的话,myLooper会返回null。接下来看看Looper.prepare()的实现:

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中。接下来看一下Looper的构造函数。

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

调用完Looper.prepare()后,需调用Looper.loop()才能使消息循环运作起来,其源码如下所示:

public static void loop() {    final Looper me = myLooper(); //1. 取出looper对象    if (me == null) {        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");    }    final MessageQueue queue = me.mQueue; //2. 取出looper绑定的message queue    // 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();    // loop time.    long tm = 0;    ...    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        ...        // Make sure that during the course of dispatching the        // identity of the thread wasn't corrupted.        final long newIdent = Binder.clearCallingIdentity();        if (ident != newIdent) {            ...        }        msg.recycleUnchecked(); // 5. 回收message对象        ...    }}

可以简单地将Looper.loop()理解成一个不断检测message queue是否有数据,若有即取出并执行回调的死循环。 接下来看一下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;}

what、arg1、arg2这些属性本文不作介绍,我们把目光集中在next、sPoolSync、sPool、sPoolSize这四个静态属性上。

当我们调用Message.obtain()时,返回了一个Message对象。Message对象使用完毕后,调用recycle()方法将其回收。其中obtain方法的代码如下所示:

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方法的实现:

public void recycle() {    if (isInUse()) {        if (gCheckRecycle) {            throw new IllegalStateException("This message cannot be recycled because it is still in use.");        }        return;    }    recycleUnchecked();}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.target为handler类型,即向handler成员的dispatchMessage方法传入msg参数,其实现如下所示:

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

这里可以看到回调了各种接口。

到目前为止,我们知道了如何处理在消息队列里面的msg对象,但仍不知道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是一次业务中所有参数的载体。

框架图如下所示:

            +------------------+            |      Handler     |            +----+--------^----+                 |        |           send  |        |  dispatch                 |        |                 v        |                +----- <---+                |          |                |  Looper  |                |          |                |          |                +---> -----+                  |      ^           enqueue|      | next                  |      |         +--------v------+----------+         |       MessageQueue       |         +--------+------^----------+                  |      |  nativePollOnce  |      |   nativeWake                  |      |+-----------------v------+---------------------+                Lower Layer

最后,留意到MessageQueue中有4个native方法:

// 初始化和销毁private native static long nativeInit();private native static void nativeDestroy(long ptr);// 等待和唤醒private native static void nativePollOnce(long ptr, int timeoutMillis);private native static void nativeWake(long ptr);// 判断native层的状态private native static boolean nativeIsIdling(long ptr);

将会在后续文章中进行介绍。

更多相关文章

  1. android之app widget(三)
  2. wm命令使用方法(修改android 分辨率)修改
  3. TabWidget/TabHost的两种使用方法
  4. location of the android sdk has not been setup in the prefer
  5. Android(安卓)Bundle类
  6. android 彻底关闭应用程序
  7. 浅谈Java中Collections.sort对List排序的两种方法
  8. 类和 Json对象
  9. Python list sort方法的具体使用

随机推荐

  1. android 事件机制图文详解-从源码角度分析
  2. power_supply子系统笔记
  3. 【Android Training - 05】与其他Apps进
  4. Eclipse与Android源码中ProGuard工具的使
  5. 手机相册的基本使用
  6. Android 软键盘的显示和隐藏
  7. OOM的出现及解决(加载图片)
  8. 零基础开发OpenGL ES 2.0学习笔记-Android
  9. android电池管理系统从上层的java到底层
  10. android sdk 兼容低版本的处理方法