Android消息处理机制、Hanlder机制(Handler、Looper、MessageQueue和Message)
·前言
长久以来,我使用Hanlder仅限于它的基本使用:post 和 sendMessage而对于Hanlder的原理和消息处理机制并不清楚。找了两篇比较深入的博客:
http://www.cnblogs.com/angeldevil/p/3340644.html AngelDevil的博客
http://blog.csdn.net/amazing7/article/details/51424038 amazing7的博客
学习了一下,又对照了源码,小有收获,俗话说“好记性不如烂笔头”,所以做一下笔记,总结一下,方便以后回顾。
·Android是消息驱动的
AngelDevil的博客的博客中指出Android是消息驱动的,这一点,看一下类ActivityThread就一目了然了。
public final class ActivityThread { //…… final ApplicationThread mAppThread = new ApplicationThread(); //…… final H mH = new H(); //…… final Handler getHandler() { return mH; } //…… private class ApplicationThread extends ApplicationThreadNative {//……} //…… private class H extends Handler {//……} //…… public static void main(String[] args) { //…… 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(),从Looper.prepareMainLooper();这一行看起,到Looper.looper(); 我们都知道,main()方法是程序的入口,方法里面就是主线程,从Looper.prepareMainLooper()到Looper.looper(),表明开启了轮询器,其间不断的进行消息的发送和处理,所以说Android确实是“消息驱动的”。 ActivityThread thread = new ActivityThread(): 表明在入口方法main()中创建了一个ActivityThread自己的对象,并通过代码
if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); }
获得ActivityThread内部的Handler,而ActivityThread源码中有这这几行代码: final ApplicationThread mAppThread = new ApplicationThread(); final H mH = new H(); final Handler getHandler() { return mH; } private class ApplicationThread extends ApplicationThreadNative {//……} private class H extends Handler {//……}
getHanlder就是H,H继承于Handler,而H(extends Handler)的handleMessage(){}中接受的都是一些系统消息。
也就是说,在主线程中,有一个Looper轮询器,在Looper.prepareMainLooper()和Looper.loop()之间创建了ActivityThread实例,并获得了ActivityThread内部的Handler实例,相当于在Looper的两个方法中间创建了Hanlder。Android正是通过这个Handler进行的消息传递。
·Looper轮询器
下面看一下Android源码中提供的Looper典型使用
/** * …… * This is a typical example of the implementation of a Looper thread, * using the separation of {@link #prepare} and {@link #loop} to create an * initial Handler to communicate with the Looper. *//这是一个Looper线程实现的典型案例,使用Looper.prepare()和Looper.loop()中间被隔开的部分创建 *//和初始化Handler,以便与Looper进行通信。 * * class LooperThread extends Thread { * public Handler mHandler; * * public void run() { * Looper.prepare(); * * mHandler = new Handler() { * public void handleMessage(Message msg) { * // process incoming messages here * } * }; * * Looper.loop(); * } * } */public final class Looper {//……}
正好与上面ActivityThead类中的用法相对应,只不过一个在主线程中(main()中),一个在子线程中。其本质用法是一样的。 下面是Looper的源码:
/** * 这个类用于为一个线程运行一个消息循环。默认的线程并没有一个消息循环与它们相关联; * 在线程中调用此类的prepare()方法来创建一个消息循环并且运行这个循环,然后调用Loop() * 来使消息循环处理消息直到这个循环被终止。 * * 大多数与消息循环的交互是通过Handler类来实现的。 * * 这是一个Looper线程实现的典型案例,通过使用Looper.prepare()和Looper.loop()中间被隔开的部分创建 * 和初始化Handler,以便与Looper进行通信。 * This is a typical example of the implementation of a Looper thread, * using the separation of {@link #prepare} and {@link #loop} to create an * initial Handler to communicate with the Looper. * * * class LooperThread extends Thread { * public Handler mHandler; * * public void run() { * Looper.prepare(); * * mHandler = new Handler() { * public void handleMessage(Message msg) { * // process incoming messages here * } * }; * * Looper.loop(); * } * }
*/public final class Looper { private static final String TAG = "Looper"; // sThreadLocal.get() 将返回null,除非你已经调用了prepare(). static final ThreadLocal sThreadLocal = new ThreadLocal(); private static Looper sMainLooper; // guarded by Looper.class final MessageQueue mQueue; final Thread mThread; private Printer mLogging; /** 将当前线程初始化为一个轮询器(looper)。(也就是在当前线程中维持一个轮询器) * 这样你就可以创建handler,handler之后会在开始轮询之前引用这个轮询器。要确保在调用 * 这个方法后调用{@link #loop()}方法,并且调用{@link #quit()}方法结束它。 */ public static void prepare() { prepare(true); }/** * 这个方法中创建了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)); } /** * 将当前线程初始化为一个轮询器(looper), 并标记为一个应用的主轮询器。 * 应用的朱轮询器由Android环境创建(在ActivityThread#main()中被调用), * 所以你不需要自己调用这个方法。可以看:{@link #prepare()}。 */ public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } /** * 返回应用的主轮询器(looper),它存在于应用的主线程。 */ public static Looper getMainLooper() { synchronized (Looper.class) { return sMainLooper; } } /** * 在当前线程中运行(轮询)消息队列。确保调用{@link #quit()}方法结束循环。 */ public static void loop() {//获取当前线程的Looper final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); }//获取Looper中的消息队列 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); }//###通过message的target(Handler)分发处理消息 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(); } } /** * 返回与当前线程关联的Looper对象,如果当前线程未关联Looper,返回null。 */ public static @Nullable Looper myLooper() { return sThreadLocal.get(); } /** * 返回与当前线程关联的 {@link MessageQueue} 对象。这个方法必须在运行着Looper的线程中 * 调用,否则会抛出空指针异常。 */ public static @NonNull MessageQueue myQueue() { return myLooper().mQueue; }/** * 私有构造方法。 * 其中创建了消息队列(MessageQueue)。获取了当前线程。 * 在prepare()方法中调用创建实例。可以通过myLooper()方法获取looper实例。 */ private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); } /** * 停止当前轮询器。 * * 使{@link #loop} 停止,不再处理消息队列中的任何消息。 *
* 轮询器停止(轮询)后,任何尝试发送消息到队列都将失败。 * 例如,{@link Handler#sendMessage(Message)} 方法将会返回false。 *
* 使用这个方法可能不安全,因为一些消息可能在轮询器结束之前没有被分发处理。 * 考虑使用{@link #quitSafely} 代替,以确保所有待完成的工作能被井井有条地完成。 *
*/ public void quit() { mQueue.quit(false); } /** * 安全停止当前轮询器。 * * 一旦消息队列中所有余下的到期的消息被分发处理,就使循环{@link #loop} 停止。 * 然而,还有一定时间到期的延迟消息不会在循环终止之前分发处理。 *
* 轮询器停止(轮询)后,任何尝试发送消息到队列都将失败。 * 例如,{@link Handler#sendMessage(Message)} 方法将会返回false。 *
*/ public void quitSafely() { mQueue.quit(true); } /** * 获得与这个轮询器关联的线程。 * * @return 轮询器的线程 */ public @NonNull Thread getThread() { return mThread; } /** * 获得轮询器的消息队列。 * * @return 轮询器的消息队列 */ public @NonNull MessageQueue getQueue() { return mQueue; }//......}
从Looper源码中可以得知: ① Looper的构造方法被私有化, 只能Looper能创建自己对象,而且在构造方法中,创建MessageQueue实例,获得当前线程。 ② 在Looper的prepare()方法中创建了一个Looper对象,并且设置给sThreadLocal(ThreadLocal③ Looper.prepare()在 一个线程中只能实例化一次,否则将抛出异常 ④ Looper的loop()方法中,要从当前Looper(Looper me = myLooper())中获得它的MessageQueue,并循环取出Message进行处理。 *myLooper()方法获得设置给ThreadLocal中的Looper,sThreadLocal.get()。 Looper的prepare()方法中调用了ThreadLocal的set()方法,myLooper()中调用了ThreadLocal的get()方法,下面看ThreadLocal的get()和set()方法:
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue();}public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value);}//获取线程t的ThreadLocalMapThreadLocalMap getMap(Thread t) { return t.threadLocals;}//为线程t的(ThreadLocalMap)threadLocals赋值void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue);}
set()方法将looper设置给当前线程,get()方法从当前线程中获得looper。 小结一下: ①Looper通过prepare()方法,创建Looper自己的对象,同时创建了一个消息队列(MessageQueue),并通过ThreadLocal的set()方法设置给了当前线程(其实是当前线程的ThreadLocalMap的Entry的value); ②Looper通过myLooper(),其实是通过sThreadLocal(ThreadLocalHanlder
看一下Hanlder的构造方法:下面是两个主要构造方法的源码:
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(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }
从Handler(Callback callback, boolean async)的mLooper = Looper.myLooper()处往下看,这是要获得当前线程的Looper,如果mLooper == null,就抛出运行时异常 mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException(//不能在没有调用Looper.prepare()的线程里创建handler. "Can’t create handler inside thread that has no called Looper.prepare()"); } 这两个构造方法中,一个是从当前线程取出与之关联的Looper,另一个要传入一个Looper,所以说要在线程中创建Handler实例,需要一个Looper。 Handler发送消息
下面是Handler发送消息内部调用流程发现Handler发送消息方法中最终调用的是sendMessageAtTime()方法,下面是消息发送的源码:
public final boolean sendMessage(Message msg){ return sendMessageDelayed(msg, 0);}public final boolean sendEmptyMessage(int what){ return sendEmptyMessageDelayed(what, 0);}public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis);}public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageAtTime(msg, uptimeMillis);}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);}public final boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r), 0);}public final boolean postAtTime(Runnable r, long uptimeMillis){ return sendMessageAtTime(getPostMessage(r), uptimeMillis);}public final boolean postAtTime(Runnable r, Object token, long uptimeMillis){ return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);}public final boolean postDelayed(Runnable r, long delayMillis){ return sendMessageDelayed(getPostMessage(r), delayMillis);}private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m;}private static Message getPostMessage(Runnable r, Object token) { Message m = Message.obtain(); m.obj = token; m.callback = r; return m;}private static void handleCallback(Message message) { message.callback.run();}
我们可以看出, ① 其他发送消息的方法最后都调用了sendMessageAtTime()方法,然后返回了enqueueMessage()方法 ② 发送空消息(sendEmptyMessage)时,其实创建了消息实体,只是没有消息内容(数据) ③ post系列方法看似发送的是Runnable,但最终调用sendMessageAtTime(Message msg, long uptimeMillis),而这个方法第一个参数是一个Message,其实发送的还是Message,看一下getPostMessage()会发现,里面创建了消息,并将Runnable赋值给message的callback。而在handler的dispatchMessage()中调用了(if (msg.callback != null))handleCallback(msg),而handleCallback()中运行了Runnable(message.callback.run()) 下面看一下此方法源码:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis);}
在这个方法中需要注意 1.msg.target = this 这是将当前handler赋值给了Message的target,而在之后Looper的loop()方法中,从MessageQueue中循环取出Message(msg)后, 调用msg.target.dispatchmessage(msg)来处理这个消息。 2.queue.enqueueMessage(msg, uptimeMillis) queue由sendMessageAtTime方法传传参而来,最终来自handler构造方法的myLooper()方法,也就是当前handler所在线程的Looper管理的MessageQueue。 也就是说,handler发送消息到当前线程的Looper的消息队列里。 Message
下面看一下Message部分的源码:public final class Message implements Parcelable { public int what; public int arg1; public int arg2; public Object obj;//...... /*package*/ Handler target; /*package*/ Runnable callback; // sometimes we store linked lists of these things /*package*/ Message next; private static final Object sPoolSync = new Object(); private static Message sPool; private static int sPoolSize = 0; private static final int MAX_POOL_SIZE = 50; private static boolean gCheckRecycle = true; /** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases.从全局池中返回一个新的消息实例。 * 使我们在很多情况下避免分配新的对象。 */ public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); }//...... /** * Return a Message instance to the global pool.回收一个消息放到全局池。 * * You MUST NOT touch the Message after calling this function because it has * effectively been freed. It is an error to recycle a message that is currently * enqueued or that is in the process of being delivered to a Handler. * 调用这个方法后你就不能再用Message,因为它已经被有效释放。回收一个正在列队或正在被 * 分配给Hanlder的过程中的Message是错误的。 *
*/ public void recycle() { if (isInUse()) { if (gCheckRecycle) { throw new IllegalStateException("This message cannot be recycled because it " + "is still in use."); } return; } recycleUnchecked(); } /** * Recycles a Message that may be in-use. * Used internally by the MessageQueue and Looper when disposing of queued Messages. */ void recycleUnchecked() { // Mark the message as in use while it remains in the recycled object pool. // Clear out all other details. flags = FLAG_IN_USE; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; sendingUid = -1; when = 0; target = null; callback = null; data = null; synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }//...... public void setTarget(Handler target) { this.target = target; } public Handler getTarget() { return target; }//...... /** * Sends this Message to the Handler specified by {@link #getTarget}. * Throws a null pointer exception if this field has not been set. */ public void sendToTarget() { target.sendMessage(this); } /** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}). * 构造器 (但是获得一个Message的首选方式是调用Message.obtain()) */ public Message() { }//......}
从Message部分源码中可以看出: 1. 创建Message实例,首选Message.obtain() 2. Message的target确实是一个Handler,而Message的callback是一个Runnable 3.Message内部保存了一个全局缓存的消息池,我们可以用obtain从缓存池获得一个消息,Message使用完后系统会调用recycle回收,如果自己new很多Message,每次使用完后不能及时回收,会占用很多内存的。 Handler处理消息
看一下Looper的loop()方法的源码:public static void loop() { final Looper me = myLooper();//获得当前线程的Looper if (me == null) {//如果为null,抛出运行时异常("没有Looper;线程中没有调用Looper.prepare() throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread." } final MessageQueue queue = me.mQueue; //从Looper中获得消息队列 // ……//开始无限循环 for (;;) {//不断从消息队列中取出消息(Message) Message msg = queue.next(); // might block 可能阻断 if (msg == null) { // No message indicates that the message queue is quitting. 如果没有消息标识(没有 return; } //…… try { //msg.target其实是一个Hanlder,Hanlder发送消息时,会把当前这个handler作为target msg.target.dispatchMessage(msg);//Hanlder分发消息 } finally { //…… } //…… msg.recycleUnchecked(); }}
代码,msg.target.dispatchMessage(msg),表明Message的target处理了消息,也就是发送消息的handler处理了消息(谁发送,谁处理),也是这个Looper所在线程的Handler处理了消息。 所以说,Looper.prepare()中创建了消息队列(MessageQueue),并与当前线程关联;Looper.loop()获得当前线程的Looper并循环遍历其管理的MessageQueue(),用Message自己的target处理消息。这个target就是当前线程Looper两个方法之间创建的handler对象。 我们就知道了,Looper的loop()方法是取出消息并处理消息的场所,而真正处理消息的对象,还是发送消息的handler。 Looper的loop()方法中使用了msg.target.dispatchMessage(msg),也就是Handler的dispatchMessage()方法,下面看一下handler的消息分发处理的源码: /** * Callback interface you can use when instantiating a Handler to avoid * having to implement your own subclass of Handler. * 实例化一个handler时,为避免必须实现你自己的Hanlder的子类,你可以使用回调接口。 */public interface Callback { public boolean handleMessage(Message msg);}/** * Subclasses must implement this to receive messages.//子类必须实现这个方法来接收消息。 */public void handleMessage(Message 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); }}private static void handleCallback(Message message) { message.callback.run();}
从源码可以看出,消息分发处理有三层: ① 当msg.callback !=null,也就是使用了handler的post系列方法发送了消息(将Runnable赋值给了message的callback),消息由handleCallback()方法处理(message.callback.run()) ② 当mCallback != null,也就是handler设置了Callback,消息就由handler的Callback的handleMessage()处理 ③ 当mCallback为空或Callback的handleMessage()处理完消息表明还有消息要处理,返回false,消息由handler子类的实现方法handleMessage()处理。 *handler的Callback的源码注释中指出,如果不想实现Handler的子类(必须实现handleMessage()方法处理消息),可以设置CallBack回调接口。 ·总结
1. 一个线程中要想创建Handler发送处理消息,要先调用Looper.prepare()和Looper.loop()来创建一个消息队列(MessageQueue)开启一个轮询器与线程关联。
2. 在Looper的两个方法中间创建Handler,handler创建时要拿到与当前线程关联的轮询器(Looper)和轮询器管理的消息队列(MessageQueue)
3. Handler发送消息(Message)其实是发送到了2中的消息队列(MessageQueue),发送消息同时,Handler将自己设置给Message的target
4. 消息是在Looper的loop()方法中循环取出处理,最终由Message的target也就是发送自己的handler处理。
Handler:
创建:在Looper.prepare()和Looper.loop()之间创建
作用:发送消息(Message)到所在线程关联的轮询器(Looper)的消息队列(MessageQueue),并将自己作为target设置给Message
处理消息,由dispatchMessage()分发给①Callback的handleMessage()、②Handler的handleMessage()或③Handler的handleCallback()处理
Looper 轮询器
创建:由自己的prepare()方法创建并关联当前线程。
作用:Looper.perpare(),创建自己的实例同时创建一个MessageQueue,并将自己设置给当前线程
Looper.loop()从当前线程拿到Looper及其MessageQueue,循环遍历MessageQueue,取出消息,交给Message的target(发送消息的handler)处理
*Looper.myLooper():获得当前线程所关联的Looper。
MessageQueue 消息队列
创建:Looper的构造方法中创建,最终由Looper的prepare()方法创建
作用:接收handler发送消息时加入进来的消息,将其放入队列中,先入先出
Message 消息
创建:优先用Message.obtain()获取实例,Handler发送消息时创建,最终由MessageQueue管理
作用:携带消息内容传递数据,或作为一个信号(what)
注意:Message在被发送时会将发送它的Handler作为target,在使用Handler的post系列方法时,传入的Runnable对象由Message的callback得到。
更多相关文章
- android在一个app程序中,打开另一个app的方法
- 从另一种方式理解Android消息处理机制
- 小米5手机Android运行程序闪退出错解决方法
- Android 查看SHA1值的方法
- Android 更新UI 只能在主线程?
- 如何正确实现Android启动屏画面的方法(避免白屏)