当在面试的时候问到Handler的消息机制的时候,虽然能够能说出来些什么。但总感觉心里空空的。工作之余网上找了一下加看了一下源码,记录一下,以便日后查看.
1.了解Handler消息机制之前先了解与消息有关的几个类:
a.Handler:消息的处理者。
b.Looper:MessageQueue的管理者。
c.MessageQueue:消息队列,用来存放Message对象的数据结构,按照“先进先出”的原则存放消息。
d.Message:消息对象。
2.顺着一个程序的思路开始,要想进行进程间的通信,我们首先要创建一个Handler:
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch (msg.what) {
case value:
break;
default:
break;
}
}
};
在new Handler的时候有没有做什么呢?我们来看一下Handler的构造函数:
public Handler() {
this(null, false);
}
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;
}
在Handler的构造函数中我们可以看到mLooper = Looper.myLooper();Looper.myLooper()做了什么能?继续往下看:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static Looper myLooper() {
return sThreadLocal.get();
}
是从ThreadLocal中get得到looper!我们好像从开始就没有初始化Looper吧。更不用说将Looper set到ThreadLocal中了,到这里主要是Looper的事情了。先将Handler放一下,来看一下Looper。3.Looper
在一个线程中,如果存在Looper对象,则必定存在MessageQueue对象,并且只存在一个Looper对象和一个MessageQueue对象。在Android系统中,除了主线程有默认的Looper对象,其它线程默认是没有Looper对象。为什么主线程有默认的Looper对象呢?我们继续看代码(ActivityThread):
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);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
我们可以找到Looper.prepareMainLooper();Looper.loop();这行代码,继续看看它做了什么:
public static void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
myLooper().mQueue.mQuitAllowed = false;
}
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
public static void loop() {
Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
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();
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
long wallStart = 0;
long threadStart = 0;
// 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);
wallStart = SystemClock.currentTimeMicro();
threadStart = SystemClock.currentThreadTimeMicro();
}
msg.target.dispatchMessage(msg);
if (logging != null) {
long wallTime = SystemClock.currentTimeMicro() - wallStart;
long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
if (logging instanceof Profiler) {
((Profiler) logging).profile(msg, wallStart, wallTime,
threadStart, threadTime);
}
}
// 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();
}
}
}
好了到这里可以看出来了sThreadLocal.get() != null的话会出RuntimeException,所以每一个Thread只能对应一个Looper,sThreadLocal.set(new Looper());所以主线程有默认的Looper对象。其它线程默认是没有Looper对象。如果想让我们新创建的线程拥有Looper对象时,我们首先应调用Looper.prepare()方法,然后再调用Looper.loop()方法。这里来总结一下Looper.prepare()和Looper.loop()的作用:prepare函数所做的事情只是在全局的sThreadLocal中存放了个新的Looper,new Looper时赋值了mQueue和mThread,也就是说Looper.prepare()实例化了Looper,并将looper放进了ThreadLocal<T>,loop():循环获取消息队列中得下一条消息( Message msg = queue.next()),如果调用的queue.next返回的msg为null则立即结束此线程(if (msg.target == null) { return; }),如果不为null则调用msg.target.dispatchMessage(此target为handler实例,即在当前线程调用到了handler的handlerMessage,如果找不到的话ctrl+单击鼠标左键),dispatchMessage()又干了什么呢:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
看到handleMessage(msg);我想应该就明白了吧!等等,好像没有Message和MessageQueue有什么关系。奥!我们光实例化了Handler,还没有sendmessage呢,继续看
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
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);
}
从上面我们可以看到这么一条顺序:handler.sendMessage()-->handler.sendMessageDelayed()-->handler.sendMessageAtTime();queue.enqueueMessage==>把msg添加到消息队列中,MessageQueue queue = mQueue??mQueue什么时候初始化的啊?在Looper.prepare() new Looper()的时候,不信来看:
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
补充一点:上面已经说了,除了主线程其它线程默认是没有Looper对象,如果想让我们新创建的线程拥有Looper对象时,我们首先应调用Looper.prepare()方法,然后再调用Looper.loop()方法。
- class LooperThread extends Thread
- {
- public Handler mHandler;
- public void run()
- {
- Looper.prepare();
- //其它需要处理的操作
- Looper.loop();
- }
- }
好了!Handler的主要运作已经明白了,来总结一下:
1.如果在ActivityThread(主线程)运行时,Looper已经创建好了并已经在循环的工作了(loop()),实例化Handler的时候只需要Looper.myLooper()获取对象就好了,这一步主线程已经帮你做好了,如果是子线程这一步需要你自己完成。
2.Handler实例化完成后,通过sendMessage方法将message放进MessageQueue中。
3.Looper的loop方法不停的循环,通过dispatchMessage方法中的sendMessage在传递给Handler。也就是我们收到消息