Android Java层 Looper 机制

写在前面

本节主讲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();
            }
        }
    }

你可能感兴趣的:(Android,Common)