研读Android源码就会发现,Handler几乎无处不在,之所以是这样,是因为Android应用程序是使用消息来驱动的,Android系统从某种意义上讲也是一个通过消息驱动的系统,本文将通过图文并茂+源码解读+举例理解的方式,来向你详解Android中的异步消息处理机制——Handler,以及MessageQueue、Message、Looper的关系。
先说Looper。我们都知道,应用程序就是一段可执行的代码,程序的功能有这段代码来实现,待代码执行完毕后,应用程序就退出了。那么作为Android中App的主线程,当代码执行完毕后,会发生啥事?如果直接退出的话,是很不合理的。所以在代码中需要有一段死循环的代码来控制程序不会因为代码的执行完毕而退出,而在这段死循环中,系统会向该应用程序不断发送消息(Message),每循环一次,应用就会处理一个消息,当没有收到消息时,程序就会进入阻塞状态,直到下一个消息的到来。那么这段死循环出现在啥地方呢?答案就在Looper中。
Looper是Android中一个类。翻译过来就是“循环者”的意思,Looper中有两个方法比较重要,loop()和PRepare()。下面看下prepare()的源码:
//Looper类public class Looper {// 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象 private static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); 。。。//在工作线程中手动调用该方法,可为该线程创建一个Looper对象,使该线程成为一个不断死循环的Looper线程(循环线程)public static final void prepare() { //获得当前线程的Looper对象的引用 if (sThreadLocal.get() != null) { //若当前线程的已经包含了Looper对象,则抛出异常报错 throw new RuntimeException("Only one Looper may be created per thread"); } //为当前线程设置一个Looper对象 sThreadLocal.set(new Looper(true)); } }其中sThreadLocal是一个在Looper中的静态对象的引用,当使用ThreadLocal维护变量时,它会为每个使用该变量的线程提供独立的变量副本;每一个线程都可以独立地改变自己的副本并且不会影响其它线程所持有的对应的副本。可以简单地把它理解成一个Map对象,它的键就是每个线程的名字,而在这里,值就是Looper对象(因为泛型为Looper类型)。所以,调用sThreadLocal.get()方法,可以获得当前线程的Looper对象的引用。至此,从prepare()方法中可以看出,一个线程中至多只能有一个Looper对象,而一旦线程有了这个Looper对象,该线程就变成了一个可以不断处理消息(在死循环中)的Looper线程。
我们来看看Looper的构造方法:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mRun = true; mThread = Thread.currentThread(); }在构造方法中,创建了一个MessageQueue(消息队列)。
接下来看看loop()方法:
public static void loop() { //获取当前线程的Looper对象 final Looper me = myLooper(); //若当前线程没有创建Looper对象,则抛异常报错 if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } //获取当前线程的消息队列MessageQueue 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 (;;) { //从消息队列中获取消息,若没有消息则阻塞(block) 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 //输出log 可忽略这段代码 Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } //这是重点,调用Message的target属性的dispatchMessage方法,并把Message对象纯过去,让dispatchMessage处理该消息 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.recycle(); } }从loop()方法可以看出,首先,通过myLooper()方法获取了该线程的Looper对象:
public static Looper myLooper() {return sThreadLocal.get();}如果这个线程没创建过Looper对象,则在这里会报错!也就是说,loop()方法必须在prepare()方法后调用。接着就进入死循环,不断的从消息队列中取出消息,如果没有消息就阻塞。调用 msg.target.dispatchMessage(msg);把消息交给msg的target的dispatchMessage方法去处理。Msg的target是什么呢?其实就是handler对象,下面会进行分析。
至此,我们可以做一个小结: 1、一个线程至多可以创建一个Looper对象;
2、一个Looper对象对应一个MessageQueue队列;
3、综合以上两点:一个线程对应一个Looper对象,对应一个MessageQueue对列;
4、loop()方法,不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。
到此为止,我们有了消息队列,和不断取出消息的方法,那么谁把消息发送到队列呢? Handler出场了。
在使用Handler的时候,我们一般会在Activity(主线程)中new一个Handler对象并重写它的handleMessage()方法,所以从源码上出发,我们先看看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()); } } //获取当前线程的Looper对象,同样是如果为空,则抛异常报错 mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } //获取Looper对应的MessageQueue队列 mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }在Handler的构造方法中,通过Looper.myLooper()获取了当前线程保存的Looper实例,然后在又获取了这个Looper实例中保存的MessageQueue(消息队列),这样就保证了handler的实例与我们Looper实例中MessageQueue关联上了。
接着来看看常用的Handler中的sendMessage()方法:
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }看的出来,无论是调用sendMessage()还是调用sendEmptyMessageDelayed()方法,都会调用sendMessageAtTime()方法,而该方法最终会调用enqueueMessage()方法:
可以看到,最重要的那句话,Message的target属性就是Handler实例。之前的loop方法中,正是将 从消息队列中取出的消息传给dispatchMessage(msg)方法中,让其处理,而这个方法是谁的呢?当时写的是msg.target,即Message的target属性的,实际上就是Handler,也就是说,折腾一圈,最终这个Message还是由发送它的Handler处理的。
最后看看dispatchMessage方法:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }可以看到在else这个分支中调用了handleMessage()方法。而handleMessage方法居然是个空方法:
/** * Subclasses must implement this to receive messages. */ public void handleMessage(Message msg) { }显而易见,调用者必须复写这个方法,以处理从消息队列中取出的消息。而我们就是通过复写handleMessage方法,并根据传过来的Message的what属性来区分是哪一条消息的:
private Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { switch (msg.what) { case value: break; default: break; } }; };至此,整个Handler异步处理消息的流程就解释完了,下面我们重新梳理一遍:
1、首先在线程中调用Looper.Prepare()方法创建并保存一个Looper的实例,该实例中创建了一个MessageQueue实例,这样一个Looper线程就创建完毕了,注意Looper实例在一个线程中只能存在一个,显然,MessageQueue也只能存在一个实例,它们是一一对应的。 2、接着Looper.loop()方法会让当前线程进入一个死循环,不断从MessageQueue中取出消息,然后回调msg.target.dispatchMessage(msg)方法处理消息。 3、在Handler的构造方法中,首先得到当前线程保存的Looper实例,并关联Looper汇总的MessageQueue。
4、在Handler的sendMessage方法中,会首先给Message的target属性赋值,赋的值就是Handler自身的引用。然后将该Message加入消息队列中。
5、在初始化Handler时,会重写Handler的handleMessage()方法,即msg.target.dispatchMessage(msg)最终调用的方法。
综上所述在一个线程中创建Handler的方式应该是这样的:
new Thread() { private Handler handler; public void run() { Looper.prepare(); handler = new Handler() { public void handleMessage(android.os.Message msg) { Log.e("TAG",Thread.currentThread().getName()); }; }; Looper.loop();还有个问题,就是在Activity中并没有调用Looper.prepare()方法和loop()方法,也可以正常启动,这是因为Activity中默认是主线程,系统会自动调用Looper.prepareMainLooper()方法创建主线程的Looper和消息队列MessageQueue:
public final class ActivityThread { public static final void main(String[] args) { ...... //应用启动时,会首先为主线程创建一个Looper对象,所以主线程默认就是Looper线程。 Looper.prepareMainLooper(); ...... ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } ...... Looper.loop(); ...... }}有时候还会这么写代码:
mHandler.post(new Runnable() { @Override public void run() { Log.e("TAG", Thread.currentThread().getName()); mTxt.setText("这是哪个线程?"); } });在run方法中执行的代码在哪个线程中?答案是在构造Handler的那个线程中,看代码:
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }在这里从getPostMessage方法中返回一个Message对象,并将Message对象的callback属性值赋为创建的Runnable对象,建议使用Message.obtain()方法总消息池中获取一个Message实例,这样可便于Message的复用,它比Message msg = new Message()的效率高、节约内存。
同样地,sendMessageDelayed方法也会调用sendMessageAtTime方法,最终又调用了enqueueMesage方法:
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); }同样enqueueMessage方法首先会将Message的target属性赋值为Handler对象的引用, 前面说了,当使用post方法时,Message的callback属性也会被赋值为Runnable对象的引用。那么如果既调用了Handler的post方法,也重写了handleMessage()方法,程序会先执行谁呢?
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }由dispatchMessage方法可以看出,如果Message的callback属性不为空,就会执行Runnable对象,即post会得到执行,而handleMessage()反复噶不会得到执行了。
作为呼应开头的结束语,我们之所以在Android源码中到处都能看到Handler的身影,就是因为Handler巧妙的处理了异步消息的操作,而仅仅暴露给开发者一个handleMessage方法,我们只需要复写它就能实现消息在线程中的转换处理,而它的的所有的核心就都在这篇博客里了。
1、 Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
2、android的消息处理机制(图+源码分析)——Looper,Handler,Message
3、Android之Handler用法总结
4、Android中的Handler机制
5、http://www.jianshu.com/p/02962454adf7
6、Android Handler机制
7、handler.post和handler.sendMessage的区别和联系
8、承香墨影 Android–多线程之Handler
新闻热点
疑难解答