- /**
- * 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.
- *
- * <p>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.
- *
- * <p>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 <em>post</em> versions allow
- * you to enqueue Runnable objects to be called by the message queue when
- * they are received; the <em>sendMessage</em> 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).
- *
- * <p>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.
- *
- * <p>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 <em>post</em> or <em>sendMessage</em> 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.
Handler在android里负责发送和处理消息。它的主要用途:
1)按计划发送消息或执行某个Runnanble(使用POST方法),类似定时器;
2)从其他线程中发送来的消息放入消息队列中,避免线程冲突(常见于更新UI线程);
用途1: 主要依靠post(Runnable)、postAtTime(Runnable, long)、postDelayed(Runnable, long)、sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTi(Message)、sendMessageDelayed(Message, long)这些方法来来完成消息调度。post方法是当到Runable对象到达就被插入到消息队列;sendMessage方法允许你把一个包含有信息的Message插入队列,而且它会Handler的handlerMessage(Message)方法中执行(该方法要求在Handler的子类中实现)。
用途2:进程间通信
有了以上的叙述, 线程间的通信也就好理解了. 假如一个handler关联了A线程上的消息队列, 那么我们可以在B线程上调用handler的相关方法向A线程上的消息队列压入一个Message, 这个Message将在A线程上得到处理.(主线程更新UI),当然也可以在子线程中得到主线程中得消息队列,操控主线程的消息队列Looper.getMainLooper()),这样都是可以的,但是没有实在的意义。。。
当向Handler post或者send消息的时候,你可以在消息队列准备好的时候立刻执行,或者指定一个延迟之前得到处理或绝对时间对它进行处理,后两个是实现了timeout、ticks或者其他timing-based的行为。
当你的应用创建一个进程时,其主线程(UI线程)会运行一个消息队列,负责管理优先级最高的应用程序对象(活动、广播接收器等)和任何他们创建的windows。你也可以创建自己的线程,通过handler与主线程进行通信,通过在你创建的线程调用的post或sendMessage方法。传入的Runnable或者消息会被插入到消息队列并且在适当的时候得到处理。
先看下类里面使用的全局变量:
- final MessageQueue mQueue;
- final Looper mLooper;
- final Callback mCallback;
- IMessenger mMessenger;
- /**
- * Default constructor associates this handler with the queue for the
- * current thread.
- *
- * If there isn't one, this handler won't be able to receive messages.
- */
- public Handler() {
- if (FIND_POTENTIAL_LEAKS) {
- final Class<? extends Handler> klass = getClass();
- if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
- (klass.getModifiers() & Modifier.STATIC) == 0) {
- Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
- klass.getCanonicalName());
- }
- }
- 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 = null;
- }
- /**
- * Constructor associates this handler with the queue for the
- * current thread and takes a callback interface in which you can handle
- * messages.
- */
- public Handler(Callback callback) {
- if (FIND_POTENTIAL_LEAKS) {
- final Class<? extends Handler> klass = getClass();
- if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
- (klass.getModifiers() & Modifier.STATIC) == 0) {
- Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
- klass.getCanonicalName());
- }
- }
- 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;
- }
- /**
- * Use the provided queue instead of the default one.
- */
- public Handler(Looper looper) {
- mLooper = looper;
- mQueue = looper.mQueue;
- mCallback = null;
- }
- /**
- * Use the provided queue instead of the default one and take a callback
- * interface in which to handle messages.
- */
- public Handler(Looper looper, Callback callback) {
- mLooper = looper;
- mQueue = looper.mQueue;
- mCallback = callback;
- }
在默认构造方法里面,handler是和当前线程的队列关联在一起,如果队列不存在,那么handler就不能接受消息。第二个有参构造方法中,需要传入一个callback接口用于处理handler传递的Message。第三个有参构造函数是传进来一个looper来代替默认的looper。第四个就是传递一个looper和callback。
在70行有个 FIND_POTENTIAL_LEAKS参数:找到潜在的泄露。看下注释:
- /*
- * 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.
- */
设置这个标记为true来检测不是静态的匿名,本地或成员类继承Handler类。这些类型的类可以带来潜在的泄漏。在Handler的构造方法里面使用到了这个参数,目的就如上所述:
- if (FIND_POTENTIAL_LEAKS) {
- final Class<? extends Handler> klass = getClass();
- if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
- (klass.getModifiers() & Modifier.STATIC) == 0) {
- Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
- klass.getCanonicalName());
- }
- }
接着下面就是Callback接口:
- /**
- * Callback interface you can use when instantiating a Handler to avoid
- * having to implement your own subclass of Handler.
- */
- public interface Callback {
- public boolean handleMessage(Message msg);
- }
当你实例化一个Handler的时候可以使用Callback接口来避免写自定义的Handler子类。这里的机制类似与Thread与runable接口的关系。
在Handler里面,子类要处理消息的话必须重写handleMessage()这个方法,因为在handler里面它是个空方法:
- /**
- * Subclasses must implement this to receive messages.
- */
- public void handleMessage(Message msg) {
- }
再来看一下:dispatchMessage()这个方法:
- /**
- * 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);
- }
- }
- private final void handleCallback(Message message) {
- message.callback.run();
- }
关于调用Message的方法,在这篇文章里面先不谈,解析Message源码的时候再说。
下面是171行的getMessageName()方法:
- <span style="font-size:14px;">/**
- * 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);
- }</span>
我们从源码中结合注释,返回传入message的name值,默认的实现是如火message.callback不为空,就返回callback的类名,或者返回一个16进制的message的what值。
再往下,191行的obtainMessage()方法:
- <span style="font-size:14px;"> /**
- * 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);
- }</span>
从一个全局消息池里面获取一个新的Message。在Message池中检索是否存在与handler实例对应的message比创建一个新的Message更高效。如果你不想创建新Message,就是用Message.obtain方法代替。
下面是几个obtainMessage的重载方法:
- <span style="font-size:14px;"> /**
- *
- * 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);
- }</span>
和上面相同,只是参数不同,为返回的Message的一些属性赋值。
在往下就是post()方法了:
- <span style="font-size:14px;">/**
- * 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);
- }</span>
把传入的Runnable对象r加入到Message队列中,这个runnable对象将在handler关联的线程中执行。如果runnable对象被正确执行返回true,如果looper遍历消息队列时退出,则返回false。在这个方法中,主要是调用了sendMessageDelayed方法。在下面会有相应的分析。
接下来,看一下其他有关post的方法(从266行到353行):
- <span style="font-size:14px;"> /**
- * Causes the Runnable r to be added to the message queue, to be run
- * at a specific time given by <var>uptimeMillis</var>.
- * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
- * 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 <var>uptimeMillis</var>.
- * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
- * 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.
- * <b>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.</b>
- *
- * @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));
- }
- </span>
postAtTime 在指定时间uptimeMillis把runnable插入到队列中去,另一个postAtTime方法又加了一个Object类型的token,在下面的sendMessageAtTime中具体分析。postDelayed在延迟delayMillis时间后插入队列。postAtFrontOfQueue把Runnable插入到队首,下一次轮询就会被执行。
下面是从队列中删除对应的runable:
- <span style="font-size:14px;"> /**
- * 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 <var>r</var> with Object
- * <var>token</var> that are in the message queue. If <var>token</var> is null,
- * all callbacks will be removed.
- */
- public final void removeCallbacks(Runnable r, Object token)
- {
- mQueue.removeMessages(this, r, token);
- }
- </span>
下面就是重头戏SendMessage:
- <span style="font-size:14px;"> /**
- * 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);
- }</span>
- <span style="font-size:14px;">/**
- * 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);
- }</span>
- <span style="font-size:14px;">/**
- * Enqueue a message into the message queue after all pending messages
- * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
- * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
- * 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)
- {
- boolean sent = false;
- MessageQueue queue = mQueue;
- if (queue != null) {
- msg.target = this;
- sent = queue.enqueueMessage(msg, uptimeMillis);
- }
- else {
- RuntimeException e = new RuntimeException(
- this + " sendMessageAtTime() called with no mQueue");
- Log.w("Looper", e.getMessage(), e);
- }
- return sent;
- }</span>
这个方法才是真正执行插入到队列的操作,把message插入到消息队列中。
像386行到427行等发送消息,均是调用sendMessageAtTime方法:
- <span style="font-size:14px;"> /**
- * 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);
- }</span>
发送空消息,使用Message.obtain()方法获得一个Message(上面已经讲道这个方法)进行发送。
在往下495行sendMessageAtFrotOfQueue:
- <span style="font-size:14px;"> /**
- * 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.
- * <b>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.</b>
- *
- * @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)
- {
- boolean sent = false;
- MessageQueue queue = mQueue;
- if (queue != null) {
- msg.target = this;
- sent = queue.enqueueMessage(msg, 0);
- }
- else {
- RuntimeException e = new RuntimeException(
- this + " sendMessageAtTime() called with no mQueue");
- Log.w("Looper", e.getMessage(), e);
- }
- return sent;
- }</span>
把一个消息插入到message queue的队首。但是我们注意到在SendMessageAtTime中插入队列代码:
- <span style="font-size:14px;">queue.enqueueMessage(msg, uptimeMillis);</span>
在uptimeMillis时间后插入到队列,而在sendMessageAtFrotOfQueue中插入队列代码:
- <span style="font-size:14px;">queue.enqueueMessage(msg, 0)</span>
按照字面意思理解,就是立即插入队列,但是立刻插入队列也不能实现插到队首。那到底是如何实现的哪?这一点,将在MessageQueue源码分析中揭晓。
从511行到535行是从消息队列中删除对应的消息:
- <span style="font-size:14px;"> /**
- * 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, true);
- }
- /**
- * Remove any pending posts of messages with code 'what' and whose obj is
- * 'object' that are in the message queue. If <var>token</var> is null,
- * all messages will be removed.
- */
- public final void removeMessages(int what, Object object) {
- mQueue.removeMessages(this, what, object, true);
- }
- /**
- * Remove any pending posts of callbacks and sent messages whose
- * <var>obj</var> is <var>token</var>. If <var>token</var> is null,
- * all callbacks and messages will be removed.
- */
- public final void removeCallbacksAndMessages(Object token) {
- mQueue.removeCallbacksAndMessages(this, token);
- }</span>
541行,检查消息队列中是否存在相对应的消息:
- <span style="font-size:14px;"> /**
- * Check if there are any pending posts of messages with code 'what' in
- * the message queue.
- */
- public final boolean hasMessages(int what) {
- return mQueue.removeMessages(this, what, null, false);
- }
- /**
- * 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.removeMessages(this, what, object, false);
- }</span>
555行:获取当前looper:
- <span style="font-size:14px;">public final Looper getLooper() {
- return mLooper;
- }</span>
往下,dump方法,从字面意思上理解:转储,具体作用,还不太了解,将在Looper源码解析中分析下。
- <span style="font-size:14px;"> 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 + " ");
- }
- }</span>
575行,获取当前Messenger:
- <span style="font-size:14px;">final IMessenger getIMessenger() {
- synchronized (mQueue) {
- if (mMessenger != null) {
- return mMessenger;
- }
- mMessenger = new MessengerImpl();
- return mMessenger;
- }
- }</span>
关于Messenger信使类,请关注以后源码分析。
591行:将一个Runnable封装成一个Message。
- <span style="font-size:14px;"> private final Message getPostMessage(Runnable r) {
- Message m = Message.obtain();
- m.callback = r;
- return m;
- }
- private final Message getPostMessage(Runnable r, Object token) {
- Message m = Message.obtain();
- m.obj = token;
- m.callback = r;
- return m;
- }</span>
getPostMessage这个方法在上面所说的post系列方法中,被广泛使用。
最后,604行,处理message里面的runnable消息,直接调用了run方法。
- <span style="font-size:14px;">private final void handleCallback(Message message) {
- message.callback.run();
- }</span>