写在前面

本节主讲Android消息循环机制中java 部分:Jave层的Looper,MessageQueue,Handler,涉及到native部分会先做简单解释跳过。后续会在第三节将jave与native 层串联起来。

涉及到的相关java的文件路径:

  • Looper.java (android-5.1.0_r3\frameworks\base\core\java\android\os)
  • MessageQueue.java (android-5.1.0_r3\frameworks\base\core\java\android\os)
  • Message.java (android-5.1.0_r3\frameworks\base\core\java\android\os)
  • Handler.java (android-5.1.0_r3\frameworks\base\core\java\android\os)

基本概念

  • Looper :负责创建消息队列,并执行消息循环。
  • MessageQueue :消息队列,消息以链表形式组织。Message不是直接加入到MessageQueue,而是通过一个与该looper绑定的handler添加进来的。
  • Message :消息的格式。
  • Handler:派发消息以及处理消息。

创建线程消息队列

主线程消息队列是在应用程序启动时,由framework层帮忙创建的,开发者无需关心。

而如果开发者希望自己创建的子线程也拥有消息循环机制,则需开发者自己去创建。

主线程消息队列的创建

消息队列是与Looper一对一绑定的,在Looper的构造函数中会创建MessageQueue。所以从Looper的构造函数开始。

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

Looper的构造函数是private的,因为每个线程中只能有一个looper,所以采用ThreadLocal来保存looper 对象。

// sThreadLocal.get() will return null unless you've called prepare().static final ThreadLocal sThreadLocal = new ThreadLocal();private static Looper sMainLooper;  // guarded by Looper.class

我们知道,系统启动应用程序的时候,就帮我们把主线程中的Looper创建好了,那是哪里创建的呢?

Android 创建应用程序的入口函数是ActivitThread.java 的main() 函数,在main() 函数中调用了Looper的静态方法prepareMainLooper(),将创建了Looper对象以及消息队列。

public static void main(String[] args) {    ...    Looper.prepareMainLooper();    ActivityThread thread = new ActivityThread();    ...    Looper.loop();    throw new RuntimeException("Main thread loop unexpectedly exited");}

Looper . prepareMainLooper()

Looper.prepareMainLooper()函数中,会先透过prepare() 创建looper,如果发现之前已经创建过,存在重复创建的话,则会抛出异常,也就是一个线程中只能有一个looper对象的存在。所以Looper中会以ThreadLocal 来保存该对象。即为该变量在每个线程中提供独立的副本。

public static void prepareMainLooper() {    prepare(false);    synchronized (Looper.class) {        if (sMainLooper != null) {            throw new IllegalStateException("The main Looper has already been prepared.");        }        sMainLooper = myLooper();    }}

prepare() 函数中,new 了一个Looper 对象,并将其保存为线程本地变量。

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对象就创建好了,它是一个ThreadLocal变量, MessageQueue也创建好了。

子线程消息队列的创建

子线程如果需要消息循环机制的话,则需要开发者主动调用Looper.prepare()创建消息队列。

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

开始消息循环

消息队列创建完之后,会调用Looper.loop() 函数进入消息循环。

此处加上时序图。

Looper.loop()

  • 检查本线程中是否存在Looper对象,不存在则会抛出异常。

    final Looper me = myLooper();if (me == null) {    throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");}
  • 进入for死循环,只有当MessageQueue.next()
    取得下一个message为null时,则认为messagequeue正在quiting,才会跳出死循环。

    for (;;) {    Message msg = queue.next(); // might block    if (msg == null) {        // No message indicates that the message queue is quitting.        return;    }
  • 获取一个message之后,就将它交给指定的handler去dispatch

    msg.target.dispatchMessage(msg);

MessageQueue机制介绍

在介绍next() 函数之前,需要先了解MessageQueue中提供的一些机制。
MessageQueue为存放message的队列

  1. 提供添加/移除message的接口

    boolean enqueueMessage(Message msg, long when);void removeMessages(Handler h, int what, Object object);
  2. 还提供了对同步消息和异步消息不同处理方式

    什么是同步消息和异步消息?
    那就需要先了解Barrier的概念。
    Barrier 意为阻碍,栅栏。顾名思义,当往queue里插入了一个barrier,会阻碍了同步消息的处理,而对异步消息没有影响。只有remove了这个barrier,queue里面的同步消息才能继续被处理。这也是同步消息与异步消息的区别所在。

    MessageQueue里提供了添加/移除barrier的接口:

    int enqueueSyncBarrier(long when);void removeSyncBarrier(int token);
  3. IdleHandler

    MessageQueue里维护了一个IdleHandler的ArrayList,那IdleHandler 是用来干什么的呢?

    private final ArrayList mIdleHandlers = new ArrayList();

    先看一下IdleHandler类的注释:

    /** * Callback interface for discovering when a thread is going to block * waiting for more messages. */public static interface IdleHandler {    /**     * Called when the message queue has run out of messages and will now     * wait for more.  Return true to keep your idle handler active, false     * to have it removed.  This may be called if there are still messages     * pending in the queue, but they are all scheduled to be dispatched     * after the current time.     */    boolean queueIdle();}

    即在空闲的时候,提供一个接口让调用者知道,以便在空闲时候做一些其他操作,比如GC。

    使用场景:ActivitThread中有一个GCIdle extends IdleHandler,在queueIdle() 中GC操作。

    final class GcIdler implements MessageQueue.IdleHandler {    @Override    public final boolean queueIdle() {        doGcIfNeeded();        return false;    }}

MessageQueue . next() 详解

next() 是至关重要的一个函数,Looper.loop()函数每次循环都会调用MessageQueue的next() 函数来获取下一个将要被处理的message。
在next() 函数中需要考虑到Barrier以及IdleHandler存在情况下的处理。
ok,下面来分析源代码。

Message next() {    // Return here if the message loop has already quit and been disposed.    // This can happen if the application tries to restart a looper after quit    // which is not supported.    final long ptr = mPtr;    if (ptr == 0) {        return null;    }    int pendingIdleHandlerCount = -1; // -1 only during first iteration    int nextPollTimeoutMillis = 0;    for (;;) {        if (nextPollTimeoutMillis != 0) {            Binder.flushPendingCommands();        }        // 这里是利用native的epoll_wait() 来实现消息等待。nextPollTimeoutMillis        // 指java层下一个将要被处理的message的时间点。那如果native的pollOnce没有因为        // epoll event 唤醒,则会在nextPollTimeoutMillis时间点返回,以便处理后续的        // message。后续第三节会再深入讲解native部分,在这里只需要将其理解为        // sleep(nextPollTimeoutMillis-now)。        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;            // msg.target == null 表示该消息为barrier message。            // 如果消息头部是barrier message,则会跳过所有同步消息,寻找异步消息进行处理。            if (msg != null && msg.target == null) {                // Stalled by a barrier.  Find the next asynchronous message in the queue.                do {                    prevMsg = msg;                    msg = msg.next;                } while (msg != null && !msg.isAsynchronous());            }            if (msg != null) {                if (now < msg.when) {                    // 如果下一个message还没有到处理事件,则将修正nextPollTimeoutMillis                    // 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 {                    // 否则就返回该message。                    // Got a message.                    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 {                // 没有消息可处理,将nextPollTimeoutMillis置为-1,表示将会永远阻塞。                // No more messages.                nextPollTimeoutMillis = -1;            }            // Process the quit message now that all pending messages have been handled.            // 所有pending message被处理完之后,才开始处理quit message。            if (mQuitting) {                dispose();                return null;            }            // 开始处理存在IdleHandler的情况。当messagequeue为空或者下一个消息            // 还没有到处理时间时,可以认为此时是idle状态。如果存在IdleHandler的话,            // 说明有人希望能够在Idle状态下处理一些事情。            // If first time idle, then get the number of idlers to run.            // Idle handles only run if the queue is empty or if the first message            // in the queue (possibly a barrier) is due to be handled in the future.            if (pendingIdleHandlerCount < 0                    && (mMessages == null || now < mMessages.when)) {                pendingIdleHandlerCount = mIdleHandlers.size();            }            if (pendingIdleHandlerCount <= 0) {                // No idle handlers to run.  Loop and wait some more.                mBlocked = true;                continue;            }            // 创建一个size至少>=4的IdleHandler 的数组            if (mPendingIdleHandlers == null) {                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];            }            // 然后将mIdleHandlers 转换为数组赋给mPendingIdleHandlers。            // 为什么这么做呢?因为后面可能需要边遍历边删除。遍历用mPendingIdleHandlers,            // 处理完根据queueIdle返回情况来决定是否删除该IdleHandler。            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);        }        // Run the idle handlers.        // We only ever reach this code block during the first iteration.        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 {                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;        // 最后,将nextPollTimeoutMillis置为0。因为在IdleHandler处理的过程中,        // 可能已经有一个新的message已经来了,那么当前线程不能进行睡眠等待状态,        // 需要立即返回检查是否有新的message是否在pending等待处理。        // 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;    }}
  1. 首先是nativePollOnce(mPtr, nextPollTimeoutMillis), 这里是利用native的epoll_wait() 来实现消息等待。
    nextPollTimeoutMillis指java层下一个将要被处理的message的时间点。后续第三节会再深入讲解native部分,在这里只需要将其理解为sleep(nextPollTimeoutMillis)。
  2. 处理Barrier message存在的情况。 msg.target == null 表示该消息为barrier message。如果消息头部是barrier message,则会跳过所有sync message,寻找async message进行处理。
  3. 如果下一个message还没有到处理时间,则将修正nextPollTimeoutMillis;否则就返回该message。
  4. 没有msg可处理,nextPollTimeoutMillis为-1,表示将会永远阻塞。
  5. 所有pending message被处理完之后,才开始处理quit message。
  6. 处理存在IdleHandler的情况
    当messagequeue为空或者下一个消息还没有到处理时间时,可以认为此时是idle状态。如果存在IdleHandler的话,说明有人希望能够在Idle状态下处理一些事情。
    首先获取mIdleHandler的size,然后创建一个size至少>=4的IdleHandler 的数组。然后将mIdleHandlers 转换为数组赋给mPendingIdleHandlers。为什么这么做呢?因为后面可能需要边遍历边删除。遍历用mPendingIdleHandlers,处理完根据queueIdle返回情况来决定是否删除该IdleHandler。
  7. 最后,将nextPollTimeoutMillis置为0。因为在IdleHandler处理的过程中,可能已经有一个新的message已经来了,所以需要立即看看是否有新的message是否在pending等待处理。

MessageQueue总结:

  • 利用barrier提供同步消息和异步消息两种处理方式。
  • 利用IdleHandler提供机会让其他人在空闲时间段做事情。

往消息队列发送消息

消息队列创建好了,消息循环也开始了,那可以往消息队列中发送消息了。

Handler的构造过程

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

需要指定一个Looper,然后从Looper中获取queue(MessageQueue).另外两个参数是:

  • callback:收到message时,调用callback进行处理。

  • async:MessageQueue的机制介绍里有提到同步消息与异步消息。默认情况下为false,即为同步消息。

发送消息,其实就是往MessageQueue中add message

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {    msg.target = this;    if (mAsynchronous) {        msg.setAsynchronous(true);    }    return queue.enqueueMessage(msg, uptimeMillis);}public final void removeMessages(int what) {    mQueue.removeMessages(this, what, null);}

发送消息主要有三种方式:
1. obtain a message and send the message.
sendMessage可能有多种封装形式,但最终都是调用enqueueMessage().
2. post a runnable
runnable 也还是会先封装成message形式。基本上也同send message。
3. runWithScissors(runnable) 发送并执行一个同步的runnable。
- 当在同一个线程时,会直接执行这个runnable,而不需要放到queue里面。
- 当不在同一个线程时,会等这个runnable执行完,才返回,不然会block在这里。也就是Handler中提供的BlockRunnable的作用。

处理消息

在前面的looper.loop()函数中,从messageQueue中获取一个message,然后交给target去dispatchMessage().
msg.target.dispatchMessage(msg);
这里的targer就是handler,

dispatchMessage()

  1. 先处理runnable的情况
  2. 不是runnable的话,交给mCallback的handleMessage, 没有指定mCallback的话,就交给handleMessage处理。继承Handler的子类需要实现handlerMessage接口。

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

BlockRunnable & runWithScissors

public final boolean runWithScissors(final Runnable r, long timeout) {    if (r == null) {        throw new IllegalArgumentException("runnable must not be null");    }    if (timeout < 0) {        throw new IllegalArgumentException("timeout must be non-negative");    }    // 当为同一个线程时,直接执行runnable,而不需要加入到消息队列    if (Looper.myLooper() == mLooper) {        r.run();        return true;    }    // new 一个BlockRunnable对象    BlockingRunnable br = new BlockingRunnable(r);    return br.postAndWait(this, timeout);}

看一下BlockRunnable的postAndWait() & run()
- post runnable之后,将调用线程变为wait状态
- runnable 执行之后,会通知wait的线程不再wait

    public boolean postAndWait(Handler handler, long timeout) {        if (!handler.post(this)) {            return false;        }        synchronized (this) {            if (timeout > 0) {                final long expirationTime = SystemClock.uptimeMillis() + timeout;                while (!mDone) {                    long delay = expirationTime - SystemClock.uptimeMillis();                    if (delay <= 0) {                        return false; // timeout                    }                    try {                        // post runnable 之后,将调用线程变为wait状态                        wait(delay);                    } catch (InterruptedException ex) {                    }                }            } else {                while (!mDone) {                    try {                        // post runnable 之后,将调用线程变为wait状态                        wait();                    } catch (InterruptedException ex) {                    }                }            }        }        return true;    }    public void run() {        try {            mTask.run();        } finally {            synchronized (this) {                mDone = true;                // runnable 执行完之后,会通知wait的线程不再wait                notifyAll();            }        }    }

更多相关文章

  1. android发现之旅之媒体按键(耳机按键播放暂停键等)处理过程
  2. :Android(安卓)dispatchTouchEvent
  3. Android重点
  4. Android中的Handler的机制与用法详解
  5. android:configChanges
  6. Android事件处理的两种模型
  7. 爱踢门之锤子自由截屏快捷键配置(中)
  8. Android(安卓)4 游戏高级编程(第2版)
  9. Android消息机制分析

随机推荐

  1. Android 中 MVC 的简单理解
  2. Android开发实例详解之IMF(Android(安卓)S
  3. Prof Android app dev: Introduction and
  4. QQ For Android试用
  5. Android内存泄漏终极解决篇(上)
  6. 【Android】性能优化:电量消耗统计
  7. Android(安卓)Studio集成百度云推送
  8. Android.bp入门指南之Android.mk转换成An
  9. android常用布局详解
  10. frameworks中增加自定义服务使其也成为系