当在面试的时候问到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()方法。
1.如果在ActivityThread(主线程)运行时,Looper已经创建好了并已经在循环的工作了(loop()),实例化Handler的时候只需要Looper.myLooper()获取对象就好了,这一步主线程已经帮你做好了,如果是子线程这一步需要你自己完成。
2.Handler实例化完成后,通过sendMessage方法将message放进MessageQueue中。
3.Looper的loop方法不停的循环,通过dispatchMessage方法中的sendMessage在传递给Handler。也就是我们收到消息