Handler机制算是我入门源码的第一节。看得比较仔细。体会较多。mark一下。
顺序:先科普一下Handler基本功,然后再细讲下源码
一、Handler目的:
目的:Handler机制来处理了子线程去更新UI线程控件问题。
二、handler,messagequeue,looper,message关系图:
其实各种书籍上都有这么一张图。但是主要是学习源码,所以还是自己手画一张“流程图”。
三、handler知识点总结:
(若以下总结都能理解,那么可以不再看本文后续源码分析;)
1)handler、Looper、Messagequeue初始化总结:在主UI实例化Looper或者子线程手工实例化looper。在Looper中实例化Messagequeue。在handler初始化在主线程或者子线程中,且handler初始化只获取looper对象,获取Messagequeue对象,因此必须先有Looper实例再有handler实例,否则handler无法获取looper、Messagequeue。
2)hanlder中写了操作主UI线程的handlemessage空方法、使用handler实例在子线程中发送消息Message
3)Looper初始化:一个线程只有一个Looper,Looper管理Messagequeue
4)主UI线程(ActivityThread)创建Looper对象,而Looper创建了Messagequeue对象(可通过其他方式创建looper)
5)在handler里使用queue(Messagequeue对象),equeueMessage插入消息到Messagequeue,在Looper的loop()方法里调用handler对象的dispatchMessage()分发消息。并通过handler的handlerMessage()方法使主UI改变。
6)Messagequeue对象和Message对象
四、逐步分析handler源码
1)handler、Looper、Messagequeue初始化:
由于初始化顺序必然是Looper ==> Messagequeue ==> handler。所以我也按照此顺序分析源码。
四、1)Looper获取:
当我启动一个程序。按照如下顺序:
ActivityManager的startActivity()==>ActivityThread的main()==》Looper.prepareMainLooper()实例化主UI线程Looper
以上实例源码,部分如下:
ActivityManager的startActivity()
- /**
- * Start an activity in this task. Brings the task to the foreground. If this task
- * is not currently active (that is, its id < 0), then a new activity for the given
- * Intent will be launched as the root of the task and the task brought to the
- * foreground. Otherwise, if this task is currently active and the Intent does not specify
- * an activity to launch in a new task, then a new activity for the given Intent will
- * be launched on top of the task and the task brought to the foreground. If this
- * task is currently active and the Intent specifies {@link Intent#FLAG_ACTIVITY_NEW_TASK}
- * or would otherwise be launched in to a new task, then the activity not launched but
- * this task be brought to the foreground and a new intent delivered to the top
- * activity if appropriate.
- *
- * <p>In other words, you generally want to use an Intent here that does not specify
- * {@link Intent#FLAG_ACTIVITY_NEW_TASK} or {@link Intent#FLAG_ACTIVITY_NEW_DOCUMENT},
- * and let the system do the right thing.</p>
- *
- * @param intent The Intent describing the new activity to be launched on the task.
- * @param options Optional launch options.
- *
- * @see Activity#startActivity(android.content.Intent, android.os.Bundle)
- */
- public void startActivity(Context context, Intent intent, Bundle options) {
- ActivityThread thread = ActivityThread.currentActivityThread();
- thread.getInstrumentation().execStartActivityFromAppTask(context,
- thread.getApplicationThread(), mAppTaskImpl, intent, options);
- }
/**
* Start an activity in this task. Brings the task to the foreground. If this task
* is not currently active (that is, its id < 0), then a new activity for the given
* Intent will be launched as the root of the task and the task brought to the
* foreground. Otherwise, if this task is currently active and the Intent does not specify
* an activity to launch in a new task, then a new activity for the given Intent will
* be launched on top of the task and the task brought to the foreground. If this
* task is currently active and the Intent specifies {@link Intent#FLAG_ACTIVITY_NEW_TASK}
* or would otherwise be launched in to a new task, then the activity not launched but
* this task be brought to the foreground and a new intent delivered to the top
* activity if appropriate.
*
* <p>In other words, you generally want to use an Intent here that does not specify
* {@link Intent#FLAG_ACTIVITY_NEW_TASK} or {@link Intent#FLAG_ACTIVITY_NEW_DOCUMENT},
* and let the system do the right thing.</p>
*
* @param intent The Intent describing the new activity to be launched on the task.
* @param options Optional launch options.
*
* @see Activity#startActivity(android.content.Intent, android.os.Bundle)
*/
public void startActivity(Context context, Intent intent, Bundle options) {
ActivityThread thread = ActivityThread.currentActivityThread();
thread.getInstrumentation().execStartActivityFromAppTask(context,
thread.getApplicationThread(), mAppTaskImpl, intent, options);
}
此处ActivityThread.currentActivityThread();
public static ActivityThread currentActivityThread() {
return sCurrentActivityThread;
}
一个单例模式的ActivityThread,简单看下定义。
- /** Reference to singleton {@link ActivityThread} */
- private static ActivityThread sCurrentActivityThread;
/** Reference to singleton {@link ActivityThread} */
private static ActivityThread sCurrentActivityThread;
ActivityThread的main()
- public static void main(String[] args) {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
- 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());
- AndroidKeyStoreProvider.install();
- // Make sure TrustedCertificateStore looks in the right place for CA certificates
- final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
- TrustedCertificateStore.setDefaultUserDirectory(configDir);
- Process.setArgV0("<pre-initialized>");
- Looper.prepareMainLooper();
- ActivityThread thread = new ActivityThread();
- thread.attach(false);
- if (sMainThreadHandler == null) {
- sMainThreadHandler = thread.getHandler();
- }
- if (false) {
- Looper.myLooper().setMessageLogging(new
- LogPrinter(Log.DEBUG, "ActivityThread"));
- }
- // End of event ActivityThreadMain.
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- Looper.loop();
- throw new RuntimeException("Main thread loop unexpectedly exited");
- }
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
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());
AndroidKeyStoreProvider.install();
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
上面是整个main方法
细心可以发现这么一条主UI线程Looper初始化实例的语句:(这个代码待会儿讲Looper时一起讲,此处知道在这初始化即可)
Looper.prepareMainLooper()
Looper.prepareMainLooper();
当然有实例,还得开启主UI线程Looper的轮询方法。看这句就知道。(这个也一会儿讲Looper讲)
Looper.loop();
讲到这儿我们主线程的Looper已经初始化完事了。接下来讲讲重中之重Looper。
四、2)Messagequeue实例化即Looper源码分析
构造方法Looper()
- private Looper(boolean quitAllowed) {
- mQueue = new MessageQueue(quitAllowed);
- mThread = Thread.currentThread();
- }
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
直接上源码可见是个private的构造方法。可见单例模式痕迹明显。肯定有对外的实例方法。接着看:private static Looper sMainLooper; // guarded by Looper.class
实例在类初始化的时候初始化了。只需要获取即可。看看有哪些能获取实例的方法:
- /**
- * 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()}
- *///主线程用来实例化Looper的,你应该永远也用不到它。
- public static void prepareMainLooper() {
- prepare(false);
- synchronized (Looper.class) {
- if (sMainLooper != null) {
- throw new IllegalStateException("The main Looper has already been prepared.");
- }
- sMainLooper = myLooper();
- }
- }
/**
* 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()}
*///主线程用来实例化Looper的,你应该永远也用不到它。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
prepareMainLooper很熟悉吧。对,就是它。主方法里面用的就是它。当然注释里面说了,主线程用来实例化Looper的,你应该永远也用不到它。然后提示你看prepare()
这里第一句代码看看。
prepare(false)
这菊花虽然短,但是千万不要忽略了。它就是那个万恶的深藏着的Looper实例所在。
- private static void prepare(boolean quitAllowed) {
- if (sThreadLocal.get() != null) {
- throw new RuntimeException("Only one Looper may be created per thread");
- }
- sThreadLocal.set(new Looper(quitAllowed));
- }
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));
}
如果ThreadLocal.get()不为空,可能你会有疑问sThreadLocal究竟是什么。后面我会认真考虑写关于ThreadLocal的技术博客的。现在只需要立即为一个存储数据的对象,对外公开了set,get方法即可。
sThreadLocal.set(new Looper(quitAllowed));
这里的quitallowed参数明显一直没变,是false会到最开始的私有的初始化函数private
looper(boolean quitallowed)。发现其实到这儿我们的Looper实例化已经完事了。quitallowed是给Messagequeue对象实例化传递的一个参数罢了。既然这样子,那就先放放,交给后面的Messagequeue去讲它的实例化方法再提。
绕了一圈,再来谈谈轮询loop()方法。
looper().loop()轮询方法
先把loop()源码奉上。在哪用到就再提一句吧,每次Looper实例化完,必须紧跟着它。因为首先要有这个轮询器(实例化),然后再将轮训器运转起来loop()。
- /**
- * 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.recycleUnchecked();
- }
- }
/**
* 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.recycleUnchecked();
}
}
现在可以一行行看代码了,先判断看看有没有轮训器?有则继续,没有就抛异常。所以,当你看到下面这个异常的时候,你就知道,你肯定没写轮训器。
- final Looper me = myLooper();
- if (me == null) {
- throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
- }
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
不要问我me是什么,me就是Looper实例。public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
获取Looper实例全部靠它,然后再看看这一行:简单明了,之前Looper已经实例化了Messagequeue,那么现在拿来用。
final MessageQueue queue = me.mQueue;
看看下面这几行。翻译很明确,确保当前binder调用是否为远程调用。调用这个clear方法,在当前进程中。将会清除之前进程的PID和UID,
重置成当前进程UID,PID。好吧,以后写个IPC文章。
- // 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();
// 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 (;;) {
}
里面的内容虽然涉及到Messagequeue这个对象和Message对象。但是其实从源码很好看出来。首先我们简化掉这些打日志的代码,
再看如下:
- for (;;) {
- Message msg = queue.next(); // might block
- if (msg == null) {
- // No message indicates that the message queue is quitting.
- return;
- }
- msg.target.dispatchMessage(msg);
- // Make sure that during the course of dispatching the
- // identity of the thread wasn't corrupted.
- final long newIdent = Binder.clearCallingIdentity();
- msg.recycleUnchecked();
- }
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg);
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
msg.recycleUnchecked();
}
天呐,我对它究竟做了什么!居然只剩下四条了。所以不要害怕,一切源码都是纸老虎。而且其中还有一条是刚刚讲过的Binder重设。
这么一看。居然只剩下三条。但是,我很无耻,我只打算在这个篇章里面讲上面两条。其它都留给messagequeue和message。
Message msg = queue.next(); // might block
一条是从“队列”中取出一条消息。
msg.target.dispatchMessage(msg);
另一条是,是讲这个消息分发出去。其中msg.target就是指向我们主线程中的handler对象。问我为什么知道的。一会儿我打算讲Message就知道了。
到这,很明显的每次从“队列”中取出一条,然后分发出去。我们轮询就干了这么间完全无技术含量的事。
Messagequeue和Message对象:
先讲Messagequeue吧:我估计我写的挺累,大家看的也挺累。再忍一忍。成功一大半了!最难的都看完了。就剩下一个操作类handler,
两个对象Messagequeue、Message对象。
Messagequeue对象:
先把遗留问题讲讲:
mQuitAllowed:这个参数传递过来做什么?看源码吧。
PS:以下都是Messagequeue的部分源码:
// True if the message queue can be quit.
private final boolean mQuitAllowed;
源码注释写的太明白了:就是判断Messagequeue能不能退出的。再深入一点。
- void quit(boolean safe) {
- if (!mQuitAllowed) {
- throw new IllegalStateException("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);
- }
- }
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("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);
}
}
Messagequeue自带退出方法。为什么不能退出?因为我们刚刚传递参数一直都是从主UI线程的Looper给的。主线程不允许Messagequeue退出,就是这么任性!既然都看到了,就简单讲讲吧。mQuitting这个标志:
If the loop is quitting then it must not be idling.
简单来说就是一个loop空转的标志。这个参数从哪来的?从Looper类的方法过来的:- /** 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);
- }
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
prepare(true);
}
其实也就是说我们自己新建的Looper对象都是可以退出,且需要退出的。而主线程是不允许的。public void quit() {
mQueue.quit(false);
}
涉及到一个是否安全退出的问题。Looper安全退出究竟是什么?
- 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.recycleUnchecked();
- } while (n != 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.recycleUnchecked();
} while (n != null);
}
}
}
大概看一眼则知道:
那么我就安全退出 方法,具体分析如:
如果p.when>now,即队首的消息执行时间大于当前时间,则表明队首的消息还没分发。等同于删除所有的消息队列的消息:那么就调用removeAllMessageLocked。删除所有。
否则删除消息执行时间大于当前时间的消息。
- private void removeAllMessagesLocked() {
- Message p = mMessages;
- while (p != null) {
- Message n = p.next;
- p.recycleUnchecked();
- p = n;
- }
- mMessages = null;
- }
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked();
p = n;
}
mMessages = null;
}
虽然比较麻烦,可还是简单要讲下MessageQueue的next()方法:主要是一些算法用来取得下一条要执行的Message对象。不打算在此处花费大量篇幅写。下一篇,会优先考虑写下这个算法。有兴趣的可以看看。Message对象:
public final class Message implements Parcelable
关键字
what用得最多的:描述很清楚的写着每个handler都有自己的独立命名空间。不用担心命名冲突问题。
- /**
- * 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;
/**
* 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;
看看构造方法:官方不推荐直接调用,推荐使用obtain获取handler 对象。性能问题。具体原因:也就是一个新建对象的开销问题。参考这篇文章:http://blog.csdn.net/h3c4lenovo/article/details/7914902- /** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
- */
- public Message() {
- }
/** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
*/
public Message() {
}
其实讲到这,Message日常用到可能也就是what,这儿补充一点内容。关于message对象的target。/*package*/ Handler target;
这个target是个handler对象,主要目的是用来指向当前使用的handler。从obtain方法可见:- /**
- * 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;
- m.sendingUid = orig.sendingUid;
- 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 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;
m.sendingUid = orig.sendingUid;
if (orig.data != null) {
m.data = new Bundle(orig.data);
}
m.target = orig.target;
m.callback = orig.callback;
return m;
}
可能看到这儿大家都看到了m.target = orig.trget。- /**
- * 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) {
- }
/**
* 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) {
}
new一个handler实例。直接上源码:- public Handler(Callback callback, boolean async) {
- 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;
- mAsynchronous = async;
- }
public Handler(Callback callback, boolean async) {
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;
mAsynchronous = async;
}
通过Looper.myLooper()获取实例。myLooper()方法我前面讲没讲?自己翻一翻。public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
可见虽然我没有传入参数最终都是要进入===》sendMessageDelayed(Message msg, long delayMillis)- public final boolean sendMessageDelayed(Message msg, long delayMillis)
- {
- if (delayMillis < 0) {
- delayMillis = 0;
- }
- return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
- }
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
进入===》sendMessageAtTime(Message msg, long uptimeMillis)下面方法为发送消息的唯一方法。所有方法均调用它。
- 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);
- }
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);
}
调用handler自己的插入消息方法。其实这是一个伪方法。真正调用的Messagequeue的该同名方法。- private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
- msg.target = this;
- if (mAsynchronous) {
- msg.setAsynchronous(true);
- }
- return queue.enqueueMessage(msg, uptimeMillis);
- }
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
说到这,消息也就发送出去了。- /**
- * 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);
- }
- }
/**
* 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);
}
}
好了,总算到了handleMessage(msg)方法了。此方法,我们实现接口的时候已然重写。那么只需调用该方法即可。