笔记:安卓App消息处理机制

内容简述

类似Binder机制,MessageQueue、Looper也有底层的C++实现,涉及文件管道和驱动等。
以下仅从Java层的Looper、Handler和MessageQueue等相关类型的源码来分析线程消息处理的机制。

MessageQueue的创建

Looper用来创建和启动消息队列。
Looper对象和线程绑定是通过ThreadLocal实现的。
它提供了各种getter方便获取线程关联的MessageQueue和Looper对象。

Looper.prepare();
Looper.prepareMainLooper();

线程通过执行Looper.prepare()来创建关联的MessageQueue。

主线程则调用prepareMainLooper()来创建主线程关联的Looper,方便其它线程向主线程发消息。

Looper.prepare()

它新建了Looper对象,以ThreadLocal存储它,所以和当前线程绑定。

构造函数中创建了消息队列:

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

MessageQueue的创建

// MessageQueue.java
private long mPtr;

MessageQueue(boolean quitAllowed) {
    mQuitAllowed = quitAllowed;
    mPtr = nativeInit();
}

nativeInit()调用C++代码创建底层的C++MessageQueue对象。
有了MessageQueue对象以后,接着需要开启消息循环,使用关联的Handler来发送、处理消息了。

消息循环

MessageQueue有点像一个阻塞队列,它提供MessageQueue.next()用来从队列中取出一个Message对象。
若没有消息则调用会阻塞。

Looper.loop()

Looper.loop()用来开启对MessageQueue的取消息操作的无限循环

public static void loop() {
    final Looper me = myLooper();
    ...
    final MessageQueue queue = me.mQueue;
    ...
    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
        ...
        msg.target.dispatchMessage(msg);
        ...
        msg.recycleUnchecked();
    }
}

可以看到,loop()的操作就是无限从queue中调用next()获取一个新Message对象,然后执行dispatchMessage来处理它。

MessageQueue.next()

nativePollOnce()用来检查队列中是否有新的消息。

参数nextPollTimeoutMillis表示在暂无消息时此次检查过程需要休眠的时间:

  • 等于-1:表示无限等待,直到被其它线程唤醒。
  • 等于 0:继续循环检查队列。
  • 大于 0:以nextPollTimeoutMillis的毫米数等待。

使用for (;😉 无限循环检查是否有消息,直到返回一个Message对象。
若当前MessageQueue正在退出,则返回null作为标识。

Message next() {
    ...
    int nextPollTimeoutMillis = 0;
    for (;;) {
        ...
        nativePollOnce(ptr, nextPollTimeoutMillis);
        ...
        synchronized (this) {
            // Try to retrieve the next message.  Return if found.
            final long now = SystemClock.uptimeMillis();
            Message msg = mMessages;
            ...
            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.
                    ...
                    mMessages = msg.next;
                    msg.next = null;
                    ...
                    return msg;
                }
            } else {
                // 继续循环等待消息
                nextPollTimeoutMillis = -1;
            }

            ...
            // 每次执行next()时,若当前没有消息可处理,那么就找到所有的idle handlers,回调它们
            ...
        }

        // 回调idle handlers. 每次调用next()只会执行一次
        ...

        // 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;
    }
}

每次调用next()时,第一次检查如果发现没有要出来的消息,就一次性调用所有在注册了的IdleHandler回调对象。

发送消息

MessageQueue和Looper对象都是和某个线程关联的。
向一个线程发送消息,通过和它绑定的一个Handler对象进行。
执行创建Handler对象的的线程,Handler对象和此线程绑定。

Handler的创建

Handler对象的构造函数中,将当前线程关联的Looper和MessageQueue保存到其字段中。

public Handler(Callback callback, boolean async) {
    ...

    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.sendMessageDelayed

每个发送到线程关联的MessageQueue中的Message对象,主要字段有:

  • long when字段表示消息预期被处理的时间;
  • int what表示消息的动作;
  • Object obj可以携带额外的数据。

发送消息的一般形式为:

boolean sendMessageAtTime(Message msg, long uptimeMillis);
boolean sendMessageDelayed(Message msg, long delayMillis);

boolean sendEmptyMessageAtTime(int what, long uptimeMillis);
boolean sendEmptyMessageDelayed(int what, long delayMillis);

若不指定when那么它为当前时间,之后被Looper取出后立即执行;

sendMessage()中将Handler Message.target设置为自身,最执行Handler绑定的队列的MessageQueue.enqueue()方法。

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

MessageQueue.enqueueMessage

字段Message Message.next用来指向Message链表中的下一个对象。
MessageQueue.mMessages字段指向了它拥有的消息链表的头结点。
mMessages中的消息根据其when的时间排列,时间近的在前面。
enqueueMessage()在添加消息时将它放到mMessages的合适的位置。

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(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) {
            // New head, wake up the event queue if blocked.
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            // Inserted within the middle of the queue.  Usually we don't have to wake
            // up the event queue unless there is a barrier at the head of the queue
            // and the message is the earliest asynchronous message in the queue.
            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;
}

mBlocked记录当前队列是否处于休眠?
在next()时若最近要处理的消息的when还未到或队列空时,则在检查队列是否空时会主动休眠一段时间。

若新的Message被添加到链表头,且它的when时间到了,那么就唤醒Looper继续执行next(),获取此Message然后处理它。

if (needWake) {
    nativeWake(mPtr);
}

消息的处理

在Looper.loop()中,每当获取新的消息后:

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

target就是发送Message的Hander。
Hander发送消息到其绑定的MessageQueue中。
可见,相关的Looper、MessageQueue、Handler都是和同一个线程关联的。

从next()的执行在Looper.loop()的循环中进行可知:
Hander.dispatchMessage()的调用就是在Looper关联的线程中进行。

Hander.dispatchMessage

public class Handler {
 final Callback mCallback;

  /**
   * Callback interface you can use when instantiating a Handler to avoid
   * having to implement your own subclass of Handler.
   *
   * @param msg A {@link android.os.Message Message} object
   * @return True if no further handling is desired
   */
  public interface Callback {
      public boolean handleMessage(Message msg);
  }

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

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

上面的Message.callback是一个Runnable。
Handler.mCallback是创建它时指定的一个回调对象。
handleMessage()就是子类重写处理自定义消息的地方。

循环和退出

Looper.loop()执行后,线程“阻塞”,不断从关联的MessageQueue中取出消息并处理。
其它线程或在处理某个消息的逻辑中,可以调用Looper.quit()退出当前线程的消息循环。

// Looper.java
final MessageQueue mQueue;
...
public void quit() {
    mQueue.quit(false);
}

它执行了MessageQueue.quit()。

void quit(boolean safe) {
    if (!mQuitAllowed) {
        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);
    }
}

这里设置mQuitting为true。
之后下次调用next()时,返回null告知Looper.loop()退出循环。
线程的消息循环结束。

(本文使用Atom编写)

posted @ 2017-01-16 19:45  everhad  阅读(390)  评论(0编辑  收藏  举报