Android Handler/AHandler消息机制分析

1.文章介绍

在这么多Android应用开发的时候,Handler一遍又一遍的出现在自己写的代码中,Handler的使用也让程序代码的流程清晰易懂。但是作为一名CODER,我不能仅仅满足熟练的使用Handler来完成消息异步事件的处理。一直以来,我都想写一篇文章来说一说Handler机制的实现,恰好最近总是接触AHandler,所以索性把两种实现放在一起来分析,有对比的同时还能加深不同层次的理解。

这是之前我想写又没有写本篇文章的原因,大概也有人跟我是同样的感觉吧。
问题1,从哪开始讲?
问题2,有什么收获?
问题3,怎么讲?

2.干货

本篇文章在Android SDK源码基础上,会分别从JAVA源码和C++源码来分析HandlerAHandler

首先看看Android Java层的Handler使用,为了方便测试写了一个很简单的DEMO

package com.example.apitestdemo;

import io.vov.vitamio.utils.Log;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

public class HandlerTest extends Activity {
    public static final String TAG = HandlerTest.class.getSimpleName();
    public static final int MSG_BASE = 0;

    Handler mainHandler = new Handler() {
        @Override
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case MSG_BASE:
                Log.d(TAG, "get message , now we can do something");
                break;
            default:
                break;
            }
        };
    };

    @Override
    protected void onCreate(Bundle arg0) {
        // TODO Auto-generated method stub
        super.onCreate(arg0);
        setContentView(R.layout.activity_main);
        
        Message msg = mainHandler.obtainMessage();
        msg.what = MSG_BASE;
        mainHandler.sendMessageDelayed(msg, 5000);
        
        Log.d(TAG, "for test , we print here");
    }

}

这是Android上面很简单的使用Handler来实现消息分发的DEMO,为了体现Handler的异步机制,特意添加了两个打印,输出如下:

06-19 11:13:48.857 D/HandlerTest ( 2001): for test , we print here
06-19 11:13:53.857 D/HandlerTest ( 2001): get message , now we can do something

在应用层使用Handler就是这么简单(在这个DEMOHandler绑定了当前Activity的线程,由这个线程维护消息队列)。
来看看Handler的完整源码:

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.os;

import android.util.Log;
import android.util.Printer;

import java.lang.reflect.Modifier;

/**
 * A Handler allows you to send and process {@link Message} and Runnable
 * objects associated with a thread's {@link MessageQueue}.  Each Handler
 * instance is associated with a single thread and that thread's message
 * queue.  When you create a new Handler, it is bound to the thread /
 * message queue of the thread that is creating it -- from that point on,
 * it will deliver messages and runnables to that message queue and execute
 * them as they come out of the message queue.
 * 
 * 

There are two main uses for a Handler: (1) to schedule messages and * runnables to be executed as some point in the future; and (2) to enqueue * an action to be performed on a different thread than your own. * *

Scheduling messages is accomplished with the * {@link #post}, {@link #postAtTime(Runnable, long)}, * {@link #postDelayed}, {@link #sendEmptyMessage}, * {@link #sendMessage}, {@link #sendMessageAtTime}, and * {@link #sendMessageDelayed} methods. The post versions allow * you to enqueue Runnable objects to be called by the message queue when * they are received; the sendMessage versions allow you to enqueue * a {@link Message} object containing a bundle of data that will be * processed by the Handler's {@link #handleMessage} method (requiring that * you implement a subclass of Handler). * *

When posting or sending to a Handler, you can either * allow the item to be processed as soon as the message queue is ready * to do so, or specify a delay before it gets processed or absolute time for * it to be processed. The latter two allow you to implement timeouts, * ticks, and other timing-based behavior. * *

When a * process is created for your application, its main thread is dedicated to * running a message queue that takes care of managing the top-level * application objects (activities, broadcast receivers, etc) and any windows * they create. You can create your own threads, and communicate back with * the main application thread through a Handler. This is done by calling * the same post or sendMessage methods as before, but from * your new thread. The given Runnable or Message will then be scheduled * in the Handler's message queue and processed when appropriate. */ public class Handler { /* * Set this flag to true to detect anonymous, local or member classes * that extend this Handler class and that are not static. These kind * of classes can potentially create leaks. */ private static final boolean FIND_POTENTIAL_LEAKS = false; private static final String TAG = "Handler"; /** * 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); } /** * Subclasses must implement this to receive messages. */ public void handleMessage(Message msg) { } /** * 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); } } /** * 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 represent 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 represent 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 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 represent 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; } /** * Returns a string representing the name of the specified message. * The default implementation will either return the class name of the * message callback if any, or the hexadecimal representation of the * message "what" field. * * @param message The message whose name is being queried */ public String getMessageName(Message message) { if (message.callback != null) { return message.callback.getClass().getName(); } return "0x" + Integer.toHexString(message.what); } /** * Returns a new {@link android.os.Message Message} from the global message pool. More efficient than * creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this). * If you don't want that facility, just call Message.obtain() instead. */ public final Message obtainMessage() { return Message.obtain(this); } /** * Same as {@link #obtainMessage()}, except that it also sets the what member of the returned Message. * * @param what Value to assign to the returned Message.what field. * @return A Message from the global message pool. */ public final Message obtainMessage(int what) { return Message.obtain(this, what); } /** * * Same as {@link #obtainMessage()}, except that it also sets the what and obj members * of the returned Message. * * @param what Value to assign to the returned Message.what field. * @param obj Value to assign to the returned Message.obj field. * @return A Message from the global message pool. */ public final Message obtainMessage(int what, Object obj) { return Message.obtain(this, what, obj); } /** * * Same as {@link #obtainMessage()}, except that it also sets the what, arg1 and arg2 members of the returned * Message. * @param what Value to assign to the returned Message.what field. * @param arg1 Value to assign to the returned Message.arg1 field. * @param arg2 Value to assign to the returned Message.arg2 field. * @return A Message from the global message pool. */ public final Message obtainMessage(int what, int arg1, int arg2) { return Message.obtain(this, what, arg1, arg2); } /** * * Same as {@link #obtainMessage()}, except that it also sets the what, obj, arg1,and arg2 values on the * returned Message. * @param what Value to assign to the returned Message.what field. * @param arg1 Value to assign to the returned Message.arg1 field. * @param arg2 Value to assign to the returned Message.arg2 field. * @param obj Value to assign to the returned Message.obj field. * @return A Message from the global message pool. */ public final Message obtainMessage(int what, int arg1, int arg2, Object obj) { return Message.obtain(this, what, arg1, arg2, obj); } /** * Causes the Runnable r to be added to the message queue. * The runnable will be run on the thread to which this handler is * attached. * * @param r The Runnable that will be executed. * * @return Returns true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } /** * Causes the Runnable r to be added to the message queue, to be run * at a specific time given by uptimeMillis. * The time-base is {@link android.os.SystemClock#uptimeMillis}. * The runnable will be run on the thread to which this handler is attached. * * @param r The Runnable that will be executed. * @param uptimeMillis The absolute time at which the callback should run, * using the {@link android.os.SystemClock#uptimeMillis} time-base. * * @return Returns true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the Runnable will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. */ public final boolean postAtTime(Runnable r, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r), uptimeMillis); } /** * Causes the Runnable r to be added to the message queue, to be run * at a specific time given by uptimeMillis. * The time-base is {@link android.os.SystemClock#uptimeMillis}. * The runnable will be run on the thread to which this handler is attached. * * @param r The Runnable that will be executed. * @param uptimeMillis The absolute time at which the callback should run, * using the {@link android.os.SystemClock#uptimeMillis} time-base. * * @return Returns true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the Runnable will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. * * @see android.os.SystemClock#uptimeMillis */ public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r, token), uptimeMillis); } /** * Causes the Runnable r to be added to the message queue, to be run * after the specified amount of time elapses. * The runnable will be run on the thread to which this handler * is attached. * * @param r The Runnable that will be executed. * @param delayMillis The delay (in milliseconds) until the Runnable * will be executed. * * @return Returns true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the Runnable will be processed -- * if the looper is quit before the delivery time of the message * occurs then the message will be dropped. */ public final boolean postDelayed(Runnable r, long delayMillis) { return sendMessageDelayed(getPostMessage(r), delayMillis); } /** * Posts a message to an object that implements Runnable. * Causes the Runnable r to executed on the next iteration through the * message queue. The runnable will be run on the thread to which this * handler is attached. * This method is only for use in very special circumstances -- it * can easily starve the message queue, cause ordering problems, or have * other unexpected side-effects. * * @param r The Runnable that will be executed. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean postAtFrontOfQueue(Runnable r) { return sendMessageAtFrontOfQueue(getPostMessage(r)); } /** * Runs the specified task synchronously. *

* If the current thread is the same as the handler thread, then the runnable * runs immediately without being enqueued. Otherwise, posts the runnable * to the handler and waits for it to complete before returning. *

* This method is dangerous! Improper use can result in deadlocks. * Never call this method while any locks are held or use it in a * possibly re-entrant manner. *

* This method is occasionally useful in situations where a background thread * must synchronously await completion of a task that must run on the * handler's thread. However, this problem is often a symptom of bad design. * Consider improving the design (if possible) before resorting to this method. *

* One example of where you might want to use this method is when you just * set up a Handler thread and need to perform some initialization steps on * it before continuing execution. *

* If timeout occurs then this method returns false but the runnable * will remain posted on the handler and may already be in progress or * complete at a later time. *

* When using this method, be sure to use {@link Looper#quitSafely} when * quitting the looper. Otherwise {@link #runWithScissors} may hang indefinitely. * (TODO: We should fix this by making MessageQueue aware of blocking runnables.) *

* * @param r The Runnable that will be executed synchronously. * @param timeout The timeout in milliseconds, or 0 to wait indefinitely. * * @return Returns true if the Runnable was successfully executed. * Returns false on failure, usually because the * looper processing the message queue is exiting. * * @hide This method is prone to abuse and should probably not be in the API. * If we ever do make it part of the API, we might want to rename it to something * less funny like runUnsafe(). */ 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"); } if (Looper.myLooper() == mLooper) { r.run(); return true; } BlockingRunnable br = new BlockingRunnable(r); return br.postAndWait(this, timeout); } /** * Remove any pending posts of Runnable r that are in the message queue. */ public final void removeCallbacks(Runnable r) { mQueue.removeMessages(this, r, null); } /** * Remove any pending posts of Runnable r with Object * token that are in the message queue. If token is null, * all callbacks will be removed. */ public final void removeCallbacks(Runnable r, Object token) { mQueue.removeMessages(this, r, token); } /** * Pushes a message onto the end of the message queue after all pending messages * before the current time. It will be received in {@link #handleMessage}, * in the thread attached to this handler. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } /** * Sends a Message containing only the what value. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); } /** * Sends a Message containing only the what value, to be delivered * after the specified amount of time elapses. * @see #sendMessageDelayed(android.os.Message, long) * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } /** * Sends a Message containing only the what value, to be delivered * at a specific time. * @see #sendMessageAtTime(android.os.Message, long) * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageAtTime(msg, uptimeMillis); } /** * Enqueue a message into the message queue after all pending messages * before (current time + delayMillis). You will receive it in * {@link #handleMessage}, in the thread attached to this handler. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the message will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. */ public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } /** * Enqueue a message into the message queue after all pending messages * before the absolute time (in milliseconds) uptimeMillis. * The time-base is {@link android.os.SystemClock#uptimeMillis}. * You will receive it in {@link #handleMessage}, in the thread attached * to this handler. * * @param uptimeMillis The absolute time at which the message should be * delivered, using the * {@link android.os.SystemClock#uptimeMillis} time-base. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the message will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. */ 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); } /** * Enqueue a message at the front of the message queue, to be processed on * the next iteration of the message loop. You will receive it in * {@link #handleMessage}, in the thread attached to this handler. * This method is only for use in very special circumstances -- it * can easily starve the message queue, cause ordering problems, or have * other unexpected side-effects. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendMessageAtFrontOfQueue(Message msg) { 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, 0); } private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); } /** * Remove any pending posts of messages with code 'what' that are in the * message queue. */ public final void removeMessages(int what) { mQueue.removeMessages(this, what, null); } /** * Remove any pending posts of messages with code 'what' and whose obj is * 'object' that are in the message queue. If object is null, * all messages will be removed. */ public final void removeMessages(int what, Object object) { mQueue.removeMessages(this, what, object); } /** * Remove any pending posts of callbacks and sent messages whose * obj is token. If token is null, * all callbacks and messages will be removed. */ public final void removeCallbacksAndMessages(Object token) { mQueue.removeCallbacksAndMessages(this, token); } /** * Check if there are any pending posts of messages with code 'what' in * the message queue. */ public final boolean hasMessages(int what) { return mQueue.hasMessages(this, what, null); } /** * Check if there are any pending posts of messages with code 'what' and * whose obj is 'object' in the message queue. */ public final boolean hasMessages(int what, Object object) { return mQueue.hasMessages(this, what, object); } /** * Check if there are any pending posts of messages with callback r in * the message queue. * * @hide */ public final boolean hasCallbacks(Runnable r) { return mQueue.hasMessages(this, r, null); } // if we can get rid of this method, the handler need not remember its loop // we could instead export a getMessageQueue() method... public final Looper getLooper() { return mLooper; } public final void dump(Printer pw, String prefix) { pw.println(prefix + this + " @ " + SystemClock.uptimeMillis()); if (mLooper == null) { pw.println(prefix + "looper uninitialized"); } else { mLooper.dump(pw, prefix + " "); } } @Override public String toString() { return "Handler (" + getClass().getName() + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}"; } final IMessenger getIMessenger() { synchronized (mQueue) { if (mMessenger != null) { return mMessenger; } mMessenger = new MessengerImpl(); return mMessenger; } } private final class MessengerImpl extends IMessenger.Stub { public void send(Message msg) { Handler.this.sendMessage(msg); } } private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; } private static Message getPostMessage(Runnable r, Object token) { Message m = Message.obtain(); m.obj = token; m.callback = r; return m; } private static void handleCallback(Message message) { message.callback.run(); } final MessageQueue mQueue; final Looper mLooper; final Callback mCallback; final boolean mAsynchronous; IMessenger mMessenger; private static final class BlockingRunnable implements Runnable { private final Runnable mTask; private boolean mDone; public BlockingRunnable(Runnable task) { mTask = task; } @Override public void run() { try { mTask.run(); } finally { synchronized (this) { mDone = true; notifyAll(); } } } 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 { wait(delay); } catch (InterruptedException ex) { } } } else { while (!mDone) { try { wait(); } catch (InterruptedException ex) { } } } } return true; } } }

按文章开篇的DEMO来分析,首先创建了一个Handler对象:

     public Handler() {
        this(null, false);
     }

     public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class 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;    //注意 Handler中的mQueue其实就是Looper中的mQueue,清楚这点对后面的分析有帮助
        mCallback = callback;
        mAsynchronous = async;
    }

这里创建了一个Looper,先看看Looper的完整源码:

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.os;

import android.util.Log;
import android.util.Printer;
import android.util.PrefixPrinter;

/**
  * Class used to run a message loop for a thread.  Threads by default do
  * not have a message loop associated with them; to create one, call
  * {@link #prepare} in the thread that is to run the loop, and then
  * {@link #loop} to have it process messages until the loop is stopped.
  * 
  * 

Most interaction with a message loop is through the * {@link Handler} class. * *

This is a typical example of the implementation of a Looper thread, * using the separation of {@link #prepare} and {@link #loop} to create an * initial Handler to communicate with the Looper. * *

  *  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();
  *      }
  *  }
*/ public final class Looper { private static final String TAG = "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 final MessageQueue mQueue; final Thread mThread; private Printer mLogging; /** 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)); } /** * Initialize the current thread as a looper, marking it as an * application's main looper. The main looper for your application * is created by the Android environment, so you should never need * to call this function yourself. See also: {@link #prepare()} */ public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } /** Returns the application's main looper, which lives in the main thread of the application. */ public static Looper getMainLooper() { synchronized (Looper.class) { return sMainLooper; } } /** * 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.recycle(); } } /** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ public static Looper myLooper() { return sThreadLocal.get(); } /** * Control logging of messages as they are processed by this Looper. If * enabled, a log message will be written to printer * at the beginning and ending of each message dispatch, identifying the * target Handler and message contents. * * @param printer A Printer object that will receive log messages, or * null to disable message logging. */ public void setMessageLogging(Printer printer) { mLogging = printer; } /** * Return the {@link MessageQueue} object associated with the current * thread. This must be called from a thread running a Looper, or a * NullPointerException will be thrown. */ public static MessageQueue myQueue() { return myLooper().mQueue; } private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); } /** * Returns true if the current thread is this looper's thread. * @hide */ public boolean isCurrentThread() { return Thread.currentThread() == mThread; } /** * Quits the looper. *

* Causes the {@link #loop} method to terminate without processing any * more messages in the message queue. *

* Any attempt to post messages to the queue after the looper is asked to quit will fail. * For example, the {@link Handler#sendMessage(Message)} method will return false. *

* Using this method may be unsafe because some messages may not be delivered * before the looper terminates. Consider using {@link #quitSafely} instead to ensure * that all pending work is completed in an orderly manner. *

* * @see #quitSafely */ public void quit() { mQueue.quit(false); } /** * Quits the looper safely. *

* Causes the {@link #loop} method to terminate as soon as all remaining messages * in the message queue that are already due to be delivered have been handled. * However pending delayed messages with due times in the future will not be * delivered before the loop terminates. *

* Any attempt to post messages to the queue after the looper is asked to quit will fail. * For example, the {@link Handler#sendMessage(Message)} method will return false. *

*/ public void quitSafely() { mQueue.quit(true); } /** * Posts a synchronization barrier to the Looper's message queue. * * Message processing occurs as usual until the message queue encounters the * synchronization barrier that has been posted. When the barrier is encountered, * later synchronous messages in the queue are stalled (prevented from being executed) * until the barrier is released by calling {@link #removeSyncBarrier} and specifying * the token that identifies the synchronization barrier. * * This method is used to immediately postpone execution of all subsequently posted * synchronous messages until a condition is met that releases the barrier. * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier * and continue to be processed as usual. * * This call must be always matched by a call to {@link #removeSyncBarrier} with * the same token to ensure that the message queue resumes normal operation. * Otherwise the application will probably hang! * * @return A token that uniquely identifies the barrier. This token must be * passed to {@link #removeSyncBarrier} to release the barrier. * * @hide */ public int postSyncBarrier() { return mQueue.enqueueSyncBarrier(SystemClock.uptimeMillis()); } /** * Removes a synchronization barrier. * * @param token The synchronization barrier token that was returned by * {@link #postSyncBarrier}. * * @throws IllegalStateException if the barrier was not found. * * @hide */ public void removeSyncBarrier(int token) { mQueue.removeSyncBarrier(token); } /** * Return the Thread associated with this Looper. */ public Thread getThread() { return mThread; } /** @hide */ public MessageQueue getQueue() { return mQueue; } /** * Return whether this looper's thread is currently idle, waiting for new work * to do. This is intrinsically racy, since its state can change before you get * the result back. * @hide */ public boolean isIdling() { return mQueue.isIdling(); } public void dump(Printer pw, String prefix) { pw.println(prefix + toString()); mQueue.dump(pw, prefix + " "); } public String toString() { return "Looper (" + mThread.getName() + ", tid " + mThread.getId() + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}"; } }

那么在创建HandlerLooper.myLooper()是什么:

static final ThreadLocal sThreadLocal = new ThreadLocal();
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static Looper myLooper() {
    return sThreadLocal.get();
}

从上面的源码看出Looper只有preparesThreadLocal才会有有效的Looper对象:
这里结合开篇的DEMO了解下Looper是如何产生的:

    /**ActivityManagerService.java*/
    private final void startProcessLocked(ProcessRecord app,
            String hostingType, String hostingNameStr) {
        if (app.pid > 0 && app.pid != MY_PID) {
            synchronized (mPidsSelfLocked) {
                mPidsSelfLocked.remove(app.pid);
                mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
            }
            app.setPid(0);
        }

        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
                "startProcessLocked removing on hold: " + app);
        mProcessesOnHold.remove(app);

        updateCpuStats();

        try {
            int uid = app.uid;

            int[] gids = null;
            int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
            if (!app.isolated) {
                int[] permGids = null;
                try {
                    final PackageManager pm = mContext.getPackageManager();
                    permGids = pm.getPackageGids(app.info.packageName);

                    if (Environment.isExternalStorageEmulated()) {
                        if (pm.checkPermission(
                                android.Manifest.permission.ACCESS_ALL_EXTERNAL_STORAGE,
                                app.info.packageName) == PERMISSION_GRANTED) {
                            mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL;
                        } else {
                            mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
                        }
                    }
                } catch (PackageManager.NameNotFoundException e) {
                    Slog.w(TAG, "Unable to retrieve gids", e);
                }

                /*
                 * Add shared application GID so applications can share some
                 * resources like shared libraries
                 */
                if (permGids == null) {
                    gids = new int[1];
                } else {
                    gids = new int[permGids.length + 1];
                    System.arraycopy(permGids, 0, gids, 1, permGids.length);
                }
                gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
            }
            if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
                if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
                        && mTopComponent != null
                        && app.processName.equals(mTopComponent.getPackageName())) {
                    uid = 0;
                }
                if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
                        && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
                    uid = 0;
                }
            }
            int debugFlags = 0;
            if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
                debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
                // Also turn on CheckJNI for debuggable apps. It's quite
                // awkward to turn on otherwise.
                debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
            }
            // Run the app in safe mode if its manifest requests so or the
            // system is booted in safe mode.
            if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
                Zygote.systemInSafeMode == true) {
                debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
            }
            if ("1".equals(SystemProperties.get("debug.checkjni"))) {
                debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
            }
            if ("1".equals(SystemProperties.get("debug.jni.logging"))) {
                debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
            }
            if ("1".equals(SystemProperties.get("debug.assert"))) {
                debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
            }

            // Start the process.  It will either succeed and return a result containing
            // the PID of the new process, or else throw a RuntimeException.
            Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, null);

            BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
            synchronized (bs) {
                if (bs.isOnBattery()) {
                    bs.getProcessStatsLocked(app.uid, app.processName).incStartsLocked();
                }
            }

            EventLog.writeEvent(EventLogTags.AM_PROC_START,
                    UserHandle.getUserId(uid), startResult.pid, uid,
                    app.processName, hostingType,
                    hostingNameStr != null ? hostingNameStr : "");

            if (app.persistent) {
                Watchdog.getInstance().processStarted(app.processName, startResult.pid);
            }

            StringBuilder buf = mStringBuilder;
            buf.setLength(0);
            buf.append("Start proc ");
            buf.append(app.processName);
            buf.append(" for ");
            buf.append(hostingType);
            if (hostingNameStr != null) {
                buf.append(" ");
                buf.append(hostingNameStr);
            }
            buf.append(": pid=");
            buf.append(startResult.pid);
            buf.append(" uid=");
            buf.append(uid);
            buf.append(" gids={");
            if (gids != null) {
                for (int gi=0; gi

在启动一个APK时,ActivityManagerService调用startProcessLocked方法(调用流程读者自己可以百度下),在startProcessLocked中:

 Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, null);

通过反射调用了ActivityThreadmain入口:

    public static void main(String[] args) {
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        Security.addProvider(new AndroidKeyStoreProvider());

        Process.setArgV0("");

        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        AsyncTask.init();

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

那么启动一个APK,就会默认创建一个依附于主进程的Looper(prepareMainLooper),最终会开始loop轮询MessageQueue队列中的消息:

    /**
     * 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.recycle();
        }
    }

所以DEMOHandlerLooper就是主进程的MainLooper,发送消息时的准备:

        Message msg = mainHandler.obtainMessage();
        msg.what = MSG_BASE;
        mainHandler.sendMessageDelayed(msg, 5000);

来看看obtainMessage:

/**Handler.java*/
public final Message obtainMessage()
{
    return Message.obtain(this);
}

Message的作用是数据Parcelable流化,以下是完整源码:

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.os;

import android.util.TimeUtils;

/**
 * 
 * Defines a message containing a description and arbitrary data object that can be
 * sent to a {@link Handler}.  This object contains two extra int fields and an
 * extra object field that allow you to not do allocations in many cases.  
 *
 * 

While the constructor of Message is public, the best way to get * one of these is to call {@link #obtain Message.obtain()} or one of the * {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull * them from a pool of recycled objects.

*/ public final class Message implements Parcelable { /** * User-defined message code so that the recipient can identify * what this message is about. Each {@link Handler} has its own name-space * for message codes, so you do not need to worry about yours conflicting * with other handlers. */ public int what; /** * arg1 and arg2 are lower-cost alternatives to using * {@link #setData(Bundle) setData()} if you only need to store a * few integer values. */ public int arg1; /** * arg1 and arg2 are lower-cost alternatives to using * {@link #setData(Bundle) setData()} if you only need to store a * few integer values. */ public int arg2; /** * An arbitrary object to send to the recipient. When using * {@link Messenger} to send the message across processes this can only * be non-null if it contains a Parcelable of a framework class (not one * implemented by the application). For other data transfer use * {@link #setData}. * *

Note that Parcelable objects here are not supported prior to * the {@link android.os.Build.VERSION_CODES#FROYO} release. */ public Object obj; /** * Optional Messenger where replies to this message can be sent. The * semantics of exactly how this is used are up to the sender and * receiver. */ public Messenger replyTo; /** If set message is in use */ /*package*/ static final int FLAG_IN_USE = 1 << 0; /** If set message is asynchronous */ /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1; /** Flags to clear in the copyFrom method */ /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE; /*package*/ int flags; /*package*/ long when; /*package*/ Bundle data; /*package*/ Handler target; /*package*/ Runnable callback; // sometimes we store linked lists of these things /*package*/ Message next; private static final Object sPoolSync = new Object(); private static Message sPool; private static int sPoolSize = 0; private static final int MAX_POOL_SIZE = 50; /** * 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; sPoolSize--; return m; } } return new Message(); } /** * Same as {@link #obtain()}, but copies the values of an existing * message (including its target) into the new one. * @param orig Original message to copy. * @return A Message object from the global pool. */ public static Message obtain(Message orig) { Message m = obtain(); m.what = orig.what; m.arg1 = orig.arg1; m.arg2 = orig.arg2; m.obj = orig.obj; m.replyTo = orig.replyTo; if (orig.data != null) { m.data = new Bundle(orig.data); } m.target = orig.target; m.callback = orig.callback; return m; } /** * Same as {@link #obtain()}, but sets the value for the target member on the Message returned. * @param h Handler to assign to the returned Message object's target member. * @return A Message object from the global pool. */ public static Message obtain(Handler h) { Message m = obtain(); m.target = h; return m; } /** * Same as {@link #obtain(Handler)}, but assigns a callback Runnable on * the Message that is returned. * @param h Handler to assign to the returned Message object's target member. * @param callback Runnable that will execute when the message is handled. * @return A Message object from the global pool. */ public static Message obtain(Handler h, Runnable callback) { Message m = obtain(); m.target = h; m.callback = callback; return m; } /** * Same as {@link #obtain()}, but sets the values for both target and * what members on the Message. * @param h Value to assign to the target member. * @param what Value to assign to the what member. * @return A Message object from the global pool. */ public static Message obtain(Handler h, int what) { Message m = obtain(); m.target = h; m.what = what; return m; } /** * Same as {@link #obtain()}, but sets the values of the target, what, and obj * members. * @param h The target value to set. * @param what The what value to set. * @param obj The object method to set. * @return A Message object from the global pool. */ public static Message obtain(Handler h, int what, Object obj) { Message m = obtain(); m.target = h; m.what = what; m.obj = obj; return m; } /** * Same as {@link #obtain()}, but sets the values of the target, what, * arg1, and arg2 members. * * @param h The target value to set. * @param what The what value to set. * @param arg1 The arg1 value to set. * @param arg2 The arg2 value to set. * @return A Message object from the global pool. */ public static Message obtain(Handler h, int what, int arg1, int arg2) { Message m = obtain(); m.target = h; m.what = what; m.arg1 = arg1; m.arg2 = arg2; return m; } /** * Same as {@link #obtain()}, but sets the values of the target, what, * arg1, arg2, and obj members. * * @param h The target value to set. * @param what The what value to set. * @param arg1 The arg1 value to set. * @param arg2 The arg2 value to set. * @param obj The obj value to set. * @return A Message object from the global pool. */ public static Message obtain(Handler h, int what, int arg1, int arg2, Object obj) { Message m = obtain(); m.target = h; m.what = what; m.arg1 = arg1; m.arg2 = arg2; m.obj = obj; return m; } /** * Return a Message instance to the global pool. You MUST NOT touch * the Message after calling this function -- it has effectively been * freed. */ public void recycle() { clearForRecycle(); synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } } /** * Make this message like o. Performs a shallow copy of the data field. * Does not copy the linked list fields, nor the timestamp or * target/callback of the original message. */ public void copyFrom(Message o) { this.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM; this.what = o.what; this.arg1 = o.arg1; this.arg2 = o.arg2; this.obj = o.obj; this.replyTo = o.replyTo; if (o.data != null) { this.data = (Bundle) o.data.clone(); } else { this.data = null; } } /** * Return the targeted delivery time of this message, in milliseconds. */ public long getWhen() { return when; } public void setTarget(Handler target) { this.target = target; } /** * Retrieve the a {@link android.os.Handler Handler} implementation that * will receive this message. The object must implement * {@link android.os.Handler#handleMessage(android.os.Message) * Handler.handleMessage()}. Each Handler has its own name-space for * message codes, so you do not need to * worry about yours conflicting with other handlers. */ public Handler getTarget() { return target; } /** * Retrieve callback object that will execute when this message is handled. * This object must implement Runnable. This is called by * the target {@link Handler} that is receiving this Message to * dispatch it. If * not set, the message will be dispatched to the receiving Handler's * {@link Handler#handleMessage(Message Handler.handleMessage())}. */ public Runnable getCallback() { return callback; } /** * Obtains a Bundle of arbitrary data associated with this * event, lazily creating it if necessary. Set this value by calling * {@link #setData(Bundle)}. Note that when transferring data across * processes via {@link Messenger}, you will need to set your ClassLoader * on the Bundle via {@link Bundle#setClassLoader(ClassLoader) * Bundle.setClassLoader()} so that it can instantiate your objects when * you retrieve them. * @see #peekData() * @see #setData(Bundle) */ public Bundle getData() { if (data == null) { data = new Bundle(); } return data; } /** * Like getData(), but does not lazily create the Bundle. A null * is returned if the Bundle does not already exist. See * {@link #getData} for further information on this. * @see #getData() * @see #setData(Bundle) */ public Bundle peekData() { return data; } /** * Sets a Bundle of arbitrary data values. Use arg1 and arg1 members * as a lower cost way to send a few simple integer values, if you can. * @see #getData() * @see #peekData() */ public void setData(Bundle data) { this.data = data; } /** * Sends this Message to the Handler specified by {@link #getTarget}. * Throws a null pointer exception if this field has not been set. */ public void sendToTarget() { target.sendMessage(this); } /** * Returns true if the message is asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with represent to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @return True if the message is asynchronous. * * @see #setAsynchronous(boolean) * @see MessageQueue#enqueueSyncBarrier(long) * @see MessageQueue#removeSyncBarrier(int) * * @hide */ public boolean isAsynchronous() { return (flags & FLAG_ASYNCHRONOUS) != 0; } /** * Sets whether the message is asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with represent to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param async True if the message is asynchronous. * * @see #isAsynchronous() * @see MessageQueue#enqueueSyncBarrier(long) * @see MessageQueue#removeSyncBarrier(int) * * @hide */ public void setAsynchronous(boolean async) { if (async) { flags |= FLAG_ASYNCHRONOUS; } else { flags &= ~FLAG_ASYNCHRONOUS; } } /*package*/ void clearForRecycle() { flags = 0; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; when = 0; target = null; callback = null; data = null; } /*package*/ boolean isInUse() { return ((flags & FLAG_IN_USE) == FLAG_IN_USE); } /*package*/ void markInUse() { flags |= FLAG_IN_USE; } /** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}). */ public Message() { } @Override public String toString() { return toString(SystemClock.uptimeMillis()); } String toString(long now) { StringBuilder b = new StringBuilder(); b.append("{ when="); TimeUtils.formatDuration(when - now, b); if (target != null) { if (callback != null) { b.append(" callback="); b.append(callback.getClass().getName()); } else { b.append(" what="); b.append(what); } if (arg1 != 0) { b.append(" arg1="); b.append(arg1); } if (arg2 != 0) { b.append(" arg2="); b.append(arg2); } if (obj != null) { b.append(" obj="); b.append(obj); } b.append(" target="); b.append(target.getClass().getName()); } else { b.append(" barrier="); b.append(arg1); } b.append(" }"); return b.toString(); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public Message createFromParcel(Parcel source) { Message msg = Message.obtain(); msg.readFromParcel(source); return msg; } public Message[] newArray(int size) { return new Message[size]; } }; public int describeContents() { return 0; } public void writeToParcel(Parcel dest, int flags) { if (callback != null) { throw new RuntimeException( "Can't marshal callbacks across processes."); } dest.writeInt(what); dest.writeInt(arg1); dest.writeInt(arg2); if (obj != null) { try { Parcelable p = (Parcelable)obj; dest.writeInt(1); dest.writeParcelable(p, flags); } catch (ClassCastException e) { throw new RuntimeException( "Can't marshal non-Parcelable objects across processes."); } } else { dest.writeInt(0); } dest.writeLong(when); dest.writeBundle(data); Messenger.writeMessengerOrNullToParcel(replyTo, dest); } private void readFromParcel(Parcel source) { what = source.readInt(); arg1 = source.readInt(); arg2 = source.readInt(); if (source.readInt() != 0) { obj = source.readParcelable(getClass().getClassLoader()); } when = source.readLong(); data = source.readBundle(); replyTo = Messenger.readMessengerOrNullFromParcel(source); } }

    /**Message.java*/
    public static Message obtain(Handler h) {
       Message m = obtain();
       m.target = h;
       return m;
    }

    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

从上面代码可以看到,Message就是一个消息池,当池里面还有可用的消息对象时,pull出这个消息重复使用,避免资源浪费,否则会新建一个Message对象。
那么sendMessageDelayed了解一下:

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

还记得Looper中的mQueue吗,发消息时在sendMessageAtTimemQueue作为参数间接调用了MessageQueueenqueueMessage接口实现排队处理,MessageQueue完整源码如下:

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.os;

import android.util.AndroidRuntimeException;
import android.util.Log;
import android.util.Printer;

import java.util.ArrayList;

/**
 * Low-level class holding the list of messages to be dispatched by a
 * {@link Looper}.  Messages are not added directly to a MessageQueue,
 * but rather through {@link Handler} objects associated with the Looper.
 * 
 * 

You can retrieve the MessageQueue for the current thread with * {@link Looper#myQueue() Looper.myQueue()}. */ public final class MessageQueue { // True if the message queue can be quit. private final boolean mQuitAllowed; @SuppressWarnings("unused") private int mPtr; // used by native code Message mMessages; private final ArrayList mIdleHandlers = new ArrayList(); private IdleHandler[] mPendingIdleHandlers; private boolean mQuitting; // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout. private boolean mBlocked; // The next barrier token. // Barriers are indicated by messages with a null target whose arg1 field carries the token. private int mNextBarrierToken; private native static int nativeInit(); private native static void nativeDestroy(int ptr); private native static void nativePollOnce(int ptr, int timeoutMillis); private native static void nativeWake(int ptr); private native static boolean nativeIsIdling(int ptr); /** * 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(); } /** * Add a new {@link IdleHandler} to this message queue. This may be * removed automatically for you by returning false from * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is * invoked, or explicitly removing it with {@link #removeIdleHandler}. * *

This method is safe to call from any thread. * * @param handler The IdleHandler to be added. */ public void addIdleHandler(IdleHandler handler) { if (handler == null) { throw new NullPointerException("Can't add a null IdleHandler"); } synchronized (this) { mIdleHandlers.add(handler); } } /** * Remove an {@link IdleHandler} from the queue that was previously added * with {@link #addIdleHandler}. If the given object is not currently * in the idle list, nothing is done. * * @param handler The IdleHandler to be removed. */ public void removeIdleHandler(IdleHandler handler) { synchronized (this) { mIdleHandlers.remove(handler); } } MessageQueue(boolean quitAllowed) { mQuitAllowed = quitAllowed; mPtr = nativeInit(); } @Override protected void finalize() throws Throwable { try { dispose(); } finally { super.finalize(); } } // Disposes of the underlying message queue. // Must only be called on the looper thread or the finalizer. private void dispose() { if (mPtr != 0) { nativeDestroy(mPtr); mPtr = 0; } } Message next() { int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } // We can assume mPtr != 0 because the loop is obviously still running. // The looper will not call this method after the loop quits. nativePollOnce(mPtr, nextPollTimeoutMillis); synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; 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) { // 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. mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; if (false) Log.v("MessageQueue", "Returning message: " + msg); msg.markInUse(); return msg; } } else { // No more messages. nextPollTimeoutMillis = -1; } // Process the quit message now that all pending messages have been handled. if (mQuitting) { dispose(); return null; } // 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; } if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } 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; // 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; } } void quit(boolean safe) { if (!mQuitAllowed) { throw new RuntimeException("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); } } int enqueueSyncBarrier(long when) { // Enqueue a new sync barrier token. // We don't need to wake the queue because the purpose of a barrier is to stall it. synchronized (this) { final int token = mNextBarrierToken++; final Message msg = Message.obtain(); msg.when = when; msg.arg1 = token; Message prev = null; Message p = mMessages; if (when != 0) { while (p != null && p.when <= when) { prev = p; p = p.next; } } if (prev != null) { // invariant: p == prev.next msg.next = p; prev.next = msg; } else { msg.next = p; mMessages = msg; } return token; } } void removeSyncBarrier(int token) { // Remove a sync barrier token from the queue. // If the queue is no longer stalled by a barrier then wake it. synchronized (this) { Message prev = null; Message p = mMessages; while (p != null && (p.target != null || p.arg1 != token)) { prev = p; p = p.next; } if (p == null) { throw new IllegalStateException("The specified message queue synchronization " + " barrier token has not been posted or has already been removed."); } final boolean needWake; if (prev != null) { prev.next = p.next; needWake = false; } else { mMessages = p.next; needWake = mMessages == null || mMessages.target != null; } p.recycle(); // If the loop is quitting then it is already awake. // We can assume mPtr != 0 when mQuitting is false. if (needWake && !mQuitting) { nativeWake(mPtr); } } } boolean enqueueMessage(Message msg, long when) { if (msg.isInUse()) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.target == null) { throw new AndroidRuntimeException("Message must have a target."); } synchronized (this) { if (mQuitting) { RuntimeException e = new RuntimeException( msg.target + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } 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; } boolean hasMessages(Handler h, int what, Object object) { if (h == null) { return false; } synchronized (this) { Message p = mMessages; while (p != null) { if (p.target == h && p.what == what && (object == null || p.obj == object)) { return true; } p = p.next; } return false; } } boolean hasMessages(Handler h, Runnable r, Object object) { if (h == null) { return false; } synchronized (this) { Message p = mMessages; while (p != null) { if (p.target == h && p.callback == r && (object == null || p.obj == object)) { return true; } p = p.next; } return false; } } boolean isIdling() { synchronized (this) { return isIdlingLocked(); } } private boolean isIdlingLocked() { // If the loop is quitting then it must not be idling. // We can assume mPtr != 0 when mQuitting is false. return !mQuitting && nativeIsIdling(mPtr); } void removeMessages(Handler h, int what, Object object) { if (h == null) { return; } synchronized (this) { Message p = mMessages; // Remove all messages at front. while (p != null && p.target == h && p.what == what && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycle(); p = n; } // Remove all messages after front. while (p != null) { Message n = p.next; if (n != null) { if (n.target == h && n.what == what && (object == null || n.obj == object)) { Message nn = n.next; n.recycle(); p.next = nn; continue; } } p = n; } } } void removeMessages(Handler h, Runnable r, Object object) { if (h == null || r == null) { return; } synchronized (this) { Message p = mMessages; // Remove all messages at front. while (p != null && p.target == h && p.callback == r && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycle(); p = n; } // Remove all messages after front. while (p != null) { Message n = p.next; if (n != null) { if (n.target == h && n.callback == r && (object == null || n.obj == object)) { Message nn = n.next; n.recycle(); p.next = nn; continue; } } p = n; } } } void removeCallbacksAndMessages(Handler h, Object object) { if (h == null) { return; } synchronized (this) { Message p = mMessages; // Remove all messages at front. while (p != null && p.target == h && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycle(); p = n; } // Remove all messages after front. while (p != null) { Message n = p.next; if (n != null) { if (n.target == h && (object == null || n.obj == object)) { Message nn = n.next; n.recycle(); p.next = nn; continue; } } p = n; } } } private void removeAllMessagesLocked() { Message p = mMessages; while (p != null) { Message n = p.next; p.recycle(); p = n; } mMessages = null; } private void removeAllFutureMessagesLocked() { final long now = SystemClock.uptimeMillis(); Message p = mMessages; if (p != null) { if (p.when > now) { removeAllMessagesLocked(); } else { Message n; for (;;) { n = p.next; if (n == null) { return; } if (n.when > now) { break; } p = n; } p.next = null; do { p = n; n = p.next; p.recycle(); } while (n != null); } } } void dump(Printer pw, String prefix) { synchronized (this) { long now = SystemClock.uptimeMillis(); int n = 0; for (Message msg = mMessages; msg != null; msg = msg.next) { pw.println(prefix + "Message " + n + ": " + msg.toString(now)); n++; } pw.println(prefix + "(Total messages: " + n + ", idling=" + isIdlingLocked() + ", quitting=" + mQuitting + ")"); } } }

下面是enqueueMessage的实现,可以看到做了类似链表的操作:

    boolean enqueueMessage(Message msg, long when) {
        if (msg.isInUse()) {
            throw new AndroidRuntimeException(msg + " This message is already in use.");
        }
        if (msg.target == null) {
            throw new AndroidRuntimeException("Message must have a target.");
        }

        synchronized (this) {
            if (mQuitting) {
                RuntimeException e = new RuntimeException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w("MessageQueue", e.getMessage(), e);
                return false;
            }

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

看到这里其实事情就明朗了,回顾下Looper中的实现:

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

这里就很明显的去轮询Looper消息队列mQueue,队列中有消息则会调用msg.target.dispatchMessage(msg);,而msg.target就是在发消息时使用的Handler对象,最后回收msg
再看看Handler中的dispatchMessage实现:

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

    public void handleMessage(Message msg) {
    }

所以在消息处理完时,就会调用子类的handleMessage,因此在DEMO中就会收到Handler分发下来的MSG_BASE消息。

当然,Handler不止这一种使用方法,在本篇文章中我只是举例了一种非常简单的使用方法,其他使用方法希望读者可以自己参考本文去分析。

Android Java源码层Handler 、 Looper 、Message就是这样构成了应用层面的消息处理机制。


Android C++源码层也有类似的消息机制,AHandler,AMessage,ALooper一起构成了这样的一个消息机制框架,很少有人直接使用这套机制写个简单易懂的DEMO,为了和上面JAVA代码保持一致,我这里自己也写了一个DEMO

/**SimpleTest.h*/
#include 
#include 
#include 

namespace android{

struct SimpleTest : public AHandler {
    SimpleTest();
    
    void testMsg();
    
protected:
    virtual ~SimpleTest();

    virtual void onMessageReceived(const sp &msg);
    
private:
    enum {
        kMsgBase,
        kMsgTest,
    };
    DISALLOW_EVIL_CONSTRUCTORS(SimpleTest);
};
}
/**SimpleTest.cpp*/
//#define LOG_NDEBUG 0

#define LOG_TAG "SimpleTest"

#include 
#include 
#include 

#include 

#include "SimpleTest.h"

namespace android {
    
SimpleTest::SimpleTest(){
        
}
    
SimpleTest::~SimpleTest(){
        
}
    
void SimpleTest::testMsg(){
    ALOGE("testMsg post");
    sp msg = new AMessage(kMsgTest, id());
    msg->setString("info", "this is info");
    msg->post(5000000); //delay 5s
}

void SimpleTest::onMessageReceived(const sp &msg){
     switch (msg->what()) {
        case kMsgTest:
        {
            ALOGE("onMessageReceived kMsgTest");
            break;
        }
        default:
        break;
     }
}

}
/**main.cpp*/
/*
 * Author:yangwu
 * Date:2018/06/20
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "HandlerTest"

#include 

#include 
#include 

#include 
#include 

#include "SimpleTest.h"

int main(int agc,char **agv){
    using namespace android;
    ProcessState::self()->startThreadPool();
    
    sp looper = new ALooper;
    looper->setName("testLooper");
    
    sp test = new SimpleTest;
    looper->registerHandler(test);
    
    looper->start(
            false, // runOnCallingThread
            false, // canCallJava
            ANDROID_PRIORITY_FOREGROUND);
    
    test->testMsg();
    ALOGE("looper here");
    while(1){
        sleep(1);
    }
    return 0;
}

输出如下:

06-20 10:40:48.491 E/SimpleTest(17844): testMsg post
06-20 10:40:48.491 E/HandlerTest(17844): looper here
06-20 10:40:53.491 E/SimpleTest(17844): onMessageReceived kMsgTest

所以通过对比可以看到Android JavaHandlerhandleMessageAndroid C++层中AHandleronMessageReceived都是回调函数,用于响应消息。

还是按照DEMO来分析实现:

    sp looper = new ALooper;
    looper->setName("testLooper");
    
    sp test = new SimpleTest;
    looper->registerHandler(test);
    
    looper->start(
            false, // runOnCallingThread
            false, // canCallJava
            ANDROID_PRIORITY_FOREGROUND);

首先来看看ALooper源码:

#ifndef A_LOOPER_H_

#define A_LOOPER_H_

#include 
#include 
#include 
#include 
#include 
#include 
#include 

namespace android {

struct AHandler;
struct AMessage;

struct ALooper : public RefBase {
    typedef int32_t event_id;
    typedef int32_t handler_id;

    ALooper();

    // Takes effect in a subsequent call to start().
    void setName(const char *name);

    handler_id registerHandler(const sp &handler);
    void unregisterHandler(handler_id handlerID);

    status_t start(
            bool runOnCallingThread = false,
            bool canCallJava = false,
            int32_t priority = PRIORITY_DEFAULT
            );

    status_t stop();

    static int64_t GetNowUs();

protected:
    virtual ~ALooper();

private:
    friend struct ALooperRoster;

    struct Event {
        int64_t mWhenUs;
        sp mMessage;
    };

    Mutex mLock;
    Condition mQueueChangedCondition;

    AString mName;

    List mEventQueue;

    struct LooperThread;
    sp mThread;
    bool mRunningLocally;

    void post(const sp &msg, int64_t delayUs);
    bool loop();

    DISALLOW_EVIL_CONSTRUCTORS(ALooper);
};

}  // namespace android

#endif  // A_LOOPER_H_
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "ALooper"
#include 

#include 

#include "ALooper.h"

#include "AHandler.h"
#include "ALooperRoster.h"
#include "AMessage.h"

namespace android {

ALooperRoster gLooperRoster;

struct ALooper::LooperThread : public Thread {
    LooperThread(ALooper *looper, bool canCallJava)
        : Thread(canCallJava),
          mLooper(looper),
          mThreadId(NULL) {
    }

    virtual status_t readyToRun() {
        mThreadId = androidGetThreadId();

        return Thread::readyToRun();
    }

    virtual bool threadLoop() {
        return mLooper->loop();
    }

    bool isCurrentThread() const {
        return mThreadId == androidGetThreadId();
    }

protected:
    virtual ~LooperThread() {}

private:
    ALooper *mLooper;
    android_thread_id_t mThreadId;

    DISALLOW_EVIL_CONSTRUCTORS(LooperThread);
};

// static
int64_t ALooper::GetNowUs() {
    return systemTime(SYSTEM_TIME_MONOTONIC) / 1000ll;
}

ALooper::ALooper()
    : mRunningLocally(false) {
}

ALooper::~ALooper() {
    stop();

    // Since this looper is "dead" (or as good as dead by now),
    // have ALooperRoster unregister any handlers still registered for it.
    gLooperRoster.unregisterStaleHandlers();
}

void ALooper::setName(const char *name) {
    mName = name;
}

ALooper::handler_id ALooper::registerHandler(const sp &handler) {
    return gLooperRoster.registerHandler(this, handler);
}

void ALooper::unregisterHandler(handler_id handlerID) {
    gLooperRoster.unregisterHandler(handlerID);
}

status_t ALooper::start(
        bool runOnCallingThread, bool canCallJava, int32_t priority) {
    if (runOnCallingThread) {
        {
            Mutex::Autolock autoLock(mLock);

            if (mThread != NULL || mRunningLocally) {
                return INVALID_OPERATION;
            }

            mRunningLocally = true;
        }

        do {
        } while (loop());

        return OK;
    }

    Mutex::Autolock autoLock(mLock);

    if (mThread != NULL || mRunningLocally) {
        return INVALID_OPERATION;
    }

    mThread = new LooperThread(this, canCallJava);

    status_t err = mThread->run(
            mName.empty() ? "ALooper" : mName.c_str(), priority);
    if (err != OK) {
        mThread.clear();
    }

    return err;
}

status_t ALooper::stop() {
    sp thread;
    bool runningLocally;

    {
        Mutex::Autolock autoLock(mLock);

        thread = mThread;
        runningLocally = mRunningLocally;
        mThread.clear();
        mRunningLocally = false;
    }

    if (thread == NULL && !runningLocally) {
        return INVALID_OPERATION;
    }

    if (thread != NULL) {
        thread->requestExit();
    }

    mQueueChangedCondition.signal();

    if (!runningLocally && !thread->isCurrentThread()) {
        // If not running locally and this thread _is_ the looper thread,
        // the loop() function will return and never be called again.
        thread->requestExitAndWait();
    }

    return OK;
}

void ALooper::post(const sp &msg, int64_t delayUs) {
    Mutex::Autolock autoLock(mLock);

    int64_t whenUs;
    if (delayUs > 0) {
        whenUs = GetNowUs() + delayUs;
    } else {
        whenUs = GetNowUs();
    }

    List::iterator it = mEventQueue.begin();
    while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) {
        ++it;
    }

    Event event;
    event.mWhenUs = whenUs;
    event.mMessage = msg;

    if (it == mEventQueue.begin()) {
        mQueueChangedCondition.signal();
    }

    mEventQueue.insert(it, event);
}

bool ALooper::loop() {
    Event event;

    {
        Mutex::Autolock autoLock(mLock);
        if (mThread == NULL && !mRunningLocally) {
            return false;
        }
        if (mEventQueue.empty()) {
            mQueueChangedCondition.wait(mLock);
            return true;
        }
        int64_t whenUs = (*mEventQueue.begin()).mWhenUs;
        int64_t nowUs = GetNowUs();

        if (whenUs > nowUs) {
            int64_t delayUs = whenUs - nowUs;
            mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);

            return true;
        }

        event = *mEventQueue.begin();
        mEventQueue.erase(mEventQueue.begin());
    }

    gLooperRoster.deliverMessage(event.mMessage);

    // NOTE: It's important to note that at this point our "ALooper" object
    // may no longer exist (its final reference may have gone away while
    // delivering the message). We have made sure, however, that loop()
    // won't be called again.

    return true;
}

}  // namespace android

可以看到Looper子类LooperThread是继承Thread的。
先是调用:

ALooper::ALooper()
    : mRunningLocally(false) {
}
void ALooper::setName(const char *name) {
    mName = name;
}
ALooper::handler_id ALooper::registerHandler(const sp &handler) {
    return gLooperRoster.registerHandler(this, handler);
}

DEMOSimpleTest是继承AHandler的子类,ALooper通过registerHandler函数和AHandler绑定起来。根据ALooper::registerHandler的实现,我们先看看gLooperRoster,源码如下:

#ifndef A_LOOPER_ROSTER_H_

#define A_LOOPER_ROSTER_H_

#include 
#include 

namespace android {

struct ALooperRoster {
    ALooperRoster();

    ALooper::handler_id registerHandler(
            const sp looper, const sp &handler);

    void unregisterHandler(ALooper::handler_id handlerID);
    void unregisterStaleHandlers();

    status_t postMessage(const sp &msg, int64_t delayUs = 0);
    void deliverMessage(const sp &msg);

    status_t postAndAwaitResponse(
            const sp &msg, sp *response);

    void postReply(uint32_t replyID, const sp &reply);

    sp findLooper(ALooper::handler_id handlerID);

private:
    struct HandlerInfo {
        wp mLooper;
        wp mHandler;
    };

    Mutex mLock;
    KeyedVector mHandlers;
    ALooper::handler_id mNextHandlerID;
    uint32_t mNextReplyID;
    Condition mRepliesCondition;

    KeyedVector > mReplies;

    status_t postMessage_l(const sp &msg, int64_t delayUs);

    DISALLOW_EVIL_CONSTRUCTORS(ALooperRoster);
};

}  // namespace android

#endif  // A_LOOPER_ROSTER_H_
//#define LOG_NDEBUG 0
#define LOG_TAG "ALooperRoster"
#include 

#include "ALooperRoster.h"

#include "ADebug.h"
#include "AHandler.h"
#include "AMessage.h"

namespace android {

ALooperRoster::ALooperRoster()
    : mNextHandlerID(1),
      mNextReplyID(1) {
}

ALooper::handler_id ALooperRoster::registerHandler(
        const sp looper, const sp &handler) {
    Mutex::Autolock autoLock(mLock);

    if (handler->id() != 0) {
        CHECK(!"A handler must only be registered once.");
        return INVALID_OPERATION;
    }

    HandlerInfo info;
    info.mLooper = looper;
    info.mHandler = handler;
    ALooper::handler_id handlerID = mNextHandlerID++;
    mHandlers.add(handlerID, info);
    ALOGW("ALooper::handler_id ALooperRoster::registerHandler %d\n",handlerID);

    handler->setID(handlerID);

    return handlerID;
}

void ALooperRoster::unregisterHandler(ALooper::handler_id handlerID) {
    Mutex::Autolock autoLock(mLock);
    ALOGI("ALooperRoster unregisterHandler handlerID=%x\n",handlerID);

    ssize_t index = mHandlers.indexOfKey(handlerID);

    if (index < 0) {
        return;
    }

    const HandlerInfo &info = mHandlers.valueAt(index);

    sp handler = info.mHandler.promote();

    if (handler != NULL) {
        handler->setID(0);
    }

    mHandlers.removeItemsAt(index);
}

void ALooperRoster::unregisterStaleHandlers() {
    Mutex::Autolock autoLock(mLock);

    for (size_t i = mHandlers.size(); i-- > 0;) {
        const HandlerInfo &info = mHandlers.valueAt(i);

        sp looper = info.mLooper.promote();
        if (looper == NULL) {
            ALOGV("Unregistering stale handler %d", mHandlers.keyAt(i));
            mHandlers.removeItemsAt(i);
        }
    }
}

status_t ALooperRoster::postMessage(
        const sp &msg, int64_t delayUs) {
    Mutex::Autolock autoLock(mLock);
    return postMessage_l(msg, delayUs);
}

status_t ALooperRoster::postMessage_l(
        const sp &msg, int64_t delayUs) {

    ssize_t index = mHandlers.indexOfKey(msg->target());

    if (index < 0) {
        ALOGW("failed to post message '%s'. Target handler not registered.",
              msg->debugString().c_str());
                 ALOGW("failed to post message 'msg->target() %d\n",msg->target());
        return -ENOENT;
    }

    const HandlerInfo &info = mHandlers.valueAt(index);

    sp looper = info.mLooper.promote();

    if (looper == NULL) {
        ALOGW("failed to post message. "
             "Target handler %d still registered, but object gone.",
             msg->target());

        mHandlers.removeItemsAt(index);
        return -ENOENT;
    }

    looper->post(msg, delayUs);

    return OK;
}

void ALooperRoster::deliverMessage(const sp &msg) {
    sp handler;

    {
        Mutex::Autolock autoLock(mLock);

        ssize_t index = mHandlers.indexOfKey(msg->target());

        if (index < 0) {
            ALOGW("failed to deliver message. Target handler not registered.");
            return;
        }

        const HandlerInfo &info = mHandlers.valueAt(index);
        handler = info.mHandler.promote();

        if (handler == NULL) {
            ALOGW("failed to deliver message. "
                 "Target handler %d registered, but object gone.",
                 msg->target());

            mHandlers.removeItemsAt(index);
            return;
        }
    }

    handler->onMessageReceived(msg);
}

sp ALooperRoster::findLooper(ALooper::handler_id handlerID) {
    Mutex::Autolock autoLock(mLock);

    ssize_t index = mHandlers.indexOfKey(handlerID);

    if (index < 0) {
        return NULL;
    }

    sp looper = mHandlers.valueAt(index).mLooper.promote();

    if (looper == NULL) {
        mHandlers.removeItemsAt(index);
        return NULL;
    }

    return looper;
}

status_t ALooperRoster::postAndAwaitResponse(
        const sp &msg, sp *response) {
    Mutex::Autolock autoLock(mLock);

    uint32_t replyID = mNextReplyID++;

    msg->setInt32("replyID", replyID);

    status_t err = postMessage_l(msg, 0 /* delayUs */);

    if (err != OK) {
        response->clear();
        return err;
    }

    ssize_t index;
    while ((index = mReplies.indexOfKey(replyID)) < 0) {
        mRepliesCondition.wait(mLock);
    }

    *response = mReplies.valueAt(index);
    mReplies.removeItemsAt(index);

    return OK;
}

void ALooperRoster::postReply(uint32_t replyID, const sp &reply) {
    Mutex::Autolock autoLock(mLock);

    CHECK(mReplies.indexOfKey(replyID) < 0);
    mReplies.add(replyID, reply);
    mRepliesCondition.broadcast();
}

}  // namespace android

其中ALooperRoster ::registerHandler函数把ALooper(这里传递的是this)和AHandler(这里是子类SimpleTest)关联在一起,把looperhandler添加到mHandlers池中,下面再来重点分析AHandler源码:

#ifndef A_HANDLER_H_

#define A_HANDLER_H_

#include 
#include 

namespace android {

struct AMessage;

struct AHandler : public RefBase {
    AHandler()
        : mID(0) {
    }

    ALooper::handler_id id() const {
        return mID;
    }

    sp looper();

protected:
    virtual void onMessageReceived(const sp &msg) = 0;

private:
    friend struct ALooperRoster;

    ALooper::handler_id mID;

    void setID(ALooper::handler_id id) {
        mID = id;
    }

    DISALLOW_EVIL_CONSTRUCTORS(AHandler);
};

}  // namespace android

#endif  // A_HANDLER_H_
//#define LOG_NDEBUG 0
#define LOG_TAG "AHandler"
#include 

#include 

#include 

namespace android {

sp AHandler::looper() {
    extern ALooperRoster gLooperRoster;

    return gLooperRoster.findLooper(id());
}

}  // namespace android

AHandler实现就很简单了,其实就是让ALooperRoster来背锅 ̄へ ̄,看下面这张图就清楚多了:

Android Handler/AHandler消息机制分析_第1张图片

ALooperAHandler创建并关联后,还需要启动ALooper:

 looper->start(
            false, // runOnCallingThread
            false, // canCallJava
            ANDROID_PRIORITY_FOREGROUND);

源码如下:

status_t ALooper::start(
        bool runOnCallingThread, bool canCallJava, int32_t priority) {
    if (runOnCallingThread) {
        {
            Mutex::Autolock autoLock(mLock);

            if (mThread != NULL || mRunningLocally) {
                return INVALID_OPERATION;
            }

            mRunningLocally = true;
        }

        do {
        } while (loop());

        return OK;
    }

    Mutex::Autolock autoLock(mLock);

    if (mThread != NULL || mRunningLocally) {
        return INVALID_OPERATION;
    }

    mThread = new LooperThread(this, canCallJava);

    status_t err = mThread->run(
            mName.empty() ? "ALooper" : mName.c_str(), priority);
    if (err != OK) {
        mThread.clear();
    }

    return err;
}

runOnCallingThreadtrue时表示在调用进程中直接loop

bool ALooper::loop() {
    Event event;

    {
        Mutex::Autolock autoLock(mLock);
        if (mThread == NULL && !mRunningLocally) {
            return false;
        }
        if (mEventQueue.empty()) {
            mQueueChangedCondition.wait(mLock);
            return true;
        }
        int64_t whenUs = (*mEventQueue.begin()).mWhenUs;
        int64_t nowUs = GetNowUs();

        if (whenUs > nowUs) {
            int64_t delayUs = whenUs - nowUs;
            mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);

            return true;
        }

        event = *mEventQueue.begin();
        mEventQueue.erase(mEventQueue.begin());
    }

    gLooperRoster.deliverMessage(event.mMessage);

    // NOTE: It's important to note that at this point our "ALooper" object
    // may no longer exist (its final reference may have gone away while
    // delivering the message). We have made sure, however, that loop()
    // won't be called again.

    return true;
}

runOnCallingThreadfalse时,创建LooperThreadrun起来,把looper作为传参:

    virtual status_t readyToRun() {
        mThreadId = androidGetThreadId();

        return Thread::readyToRun();
    }

    virtual bool threadLoop() {
        return mLooper->loop();
    }

在线程的threadLoop中,清晰的看到了ALooper::loop的调用,根据loop函数的实现可以知道最终通过LooperRoster::deliverMessage来分发消息:

void ALooperRoster::deliverMessage(const sp &msg) {
    sp handler;

    {
        Mutex::Autolock autoLock(mLock);

        ssize_t index = mHandlers.indexOfKey(msg->target());

        if (index < 0) {
            ALOGW("failed to deliver message. Target handler not registered.");
            return;
        }

        const HandlerInfo &info = mHandlers.valueAt(index);
        handler = info.mHandler.promote();

        if (handler == NULL) {
            ALOGW("failed to deliver message. "
                 "Target handler %d registered, but object gone.",
                 msg->target());

            mHandlers.removeItemsAt(index);
            return;
        }
    }

    handler->onMessageReceived(msg);
}

从上面的源码中看到,mHandlers池里面去除消息对应的AHandler对象,然后调用对应的onMessageReceived函数发送消息,因此在DEMO中的SimpleTest实现的onMessageReceived函数就能收到对应的kMsgTest消息。

虽然AHandlerAndroidlibstagefright中实现的,但从这里看起来,完全可以封装起来作为一个共享库。这和本文无关,后面我打算精简出来放到git上。

3.结束语

到这里,本篇文章就该结束了,我在Android源码基础上分别从JAVA层和C++层来分析了Handler/AHandler消息机制,可以看到两种方式设计模式基本是一样的,这种优秀的设计模式在Android源码中到处可见,也希望自己乃至读者能在其他业务中灵活的运用这种消息机制。

你可能感兴趣的:(Android Handler/AHandler消息机制分析)