/**
* 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;
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.
*/
//定义一个处理消息的内部接口,马蛋,接口真多,何时调用,返回值也很重要
public interface Callback {
public boolean handleMessage(Message msg);
}
/***
* Subclasses must implement this to receive messages.
*/
//子类需要实现该方法以处理消息,我们的自由
public void handleMessage(Message msg) {
}
//一般不会主动调用吧
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
//设置了callback时的处理方法
if (mCallback != null) {
//接口是否实现,该callback必须含有handlemessage方法,看返回值
if (mCallback.handleMessage(msg)) {
return;
}
}
//最后调用本身的handlemessage
handleMessage(msg);
}
}
/***
* 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.
*/
//默认构造函数,和当前线程的消息队列绑定,如果当前线程没有looper,则不能创建handler
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());
}
}
//获取当前looper
mLooper = Looper.myLooper();
if (mLooper == null) {
//创建handler的前提是该线程拥有looper
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.
*/
//不使用默认的looper
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;
}
/***
* 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
*/
//获取消息的名字,message.callback?
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.
*/
//直接调用message的方法,传入handler的意义
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.
*/
//将runnable对象添加到消息队列
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));
}
/***
* 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.
*/
//其调用了endMessageAtTime,也是将一个消息入队而已,时间靠什么定义而已
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)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
//target对象,嗯
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;
}
/***
* 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)
{
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;
}
/***
* 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 token 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
* 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.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);
}
// 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))
+ "}";
}
//IMessenger是个什么东西,一个远程消息对象,这个可以实现进程间基于消息的通信
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
//原来在这里,是一个内部类,只实现了一个send方法
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
//把handler传递给远程对象,远程对象直接向该handler发送消息,真简单额
Handler.this.sendMessage(msg);
}
}
//将runnable转换为message,,,,message拥有一个callback,我擦这样啊,变态玩意
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;
}
//处理消息的回调,调用message的callback的run方法,因为callback是一个runnable
private final void handleCallback(Message message) {
message.callback.run();
}
//消息队列 消息循环 回调 messenger对象
//handler是与这些进行绑定的
final MessageQueue mQueue;
final Looper mLooper;
//这个是内部的接口
final Callback mCallback;
IMessenger mMessenger;
}