消息驱动模式是android提供的用来更新UI的一套机制,即消息处理的机制,类似于Windows的消息机制,所有的外部来的按键消息、触屏消息、各种系统Intent、广播等都转化为内部消息,然后在主线程中分发处理。在Windows的消息处理模型中,存在一个系统消息队列,这个队列是整个进程的核心,几乎所有的动作都要转化成消息,然后放在队列中,消息的处理只能在主线程中完成。Android的消息处理则不太一样。Android没有全局的消息队列,消息队列是和某个线程关联在一起的。每个线程最多有一个消息队列,消息的取出和处理在线程中完成。
为什么要是用消息机制 Android在一个程序启动后会创建一个主线程,也叫UI线程(非线程安全) 这个线程主要负责监听屏幕点击事件与界面绘制,不可以直接在子线程修改UI。之所以设计成单线程模型的UI主线程,是因为多个线程访问UI可能会导致冲突,造成界面显示错乱,例如,子线程A和子线程B同时修改一个组件的尺寸和背景等资源的情况,如果非要用多线程同步加锁机制更新UI又会导致性能下降。Android在设计的时候,提供了一种异步回调机制,在子线程中用Handler通知UI线程显示、更新UI。同时,Android系统也会将大部分耗时的任务(网络访问 ,访问数据库 )交给子线程处理,当子线程完成任务将通过Handler将结果回传给UI线程,显示任务的结果。这种机制同时避免的***ANR(Application Not Responding) ***,即应用无响应。
消息机制涉及的类
Looper : 消息循环,Looper 内部有一个消息队列MessageQueue ,默认情况下一个线程不包含一个消息循环,需要自己去创建,调用**Looper.prepare()创建一个消息循环,调用 Looper.Looper()*执行这个循环,Android启动时,为 主线程(UI线程)创建了一个 Looper*对象。
Message :消息,定义一个包含描述和任意数据对象的消息发送给一个Handler ,包含两个int 数据区域和一个对象数据区域。消息的创建最好用Message.obtain()或 Handler.obtainMessage() 方法,从一个消息池中回收。
MessageQueue :消息队列,持有一个Looper 分发的消息列表,Message 不是直接添加到消息队列里的,是添加到Handler 对象绑定的Looper 的对象中。
Handler : 发送和处理消息(Message 和Runnable 对象),与一个线程的MessageQueue 关联。一个Handler 实例与一个线程(包括线程的消息队列)绑定。当一个Handler 实例被创建时,该实例与创建它的线程/线程的消息队列 绑定到一起,然后向该消息队列发送Message 和Runnable ,并且当发送的Message 和Runnable 从消息队列返回时处理它们。
Looper类 主要成员和方法 1 2 3 4 5 6 7 8 9 10 public final class Looper { static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal <Looper>(); private static Looper sMainLooper; final MessageQueue mQueue; final Thread mThread; public static void prepare () public static void prepareMainLooper () public static Looper getMainLooper () public static void loop () }
prepare() 1 2 3 4 5 6 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 类的实例对象,Looper类的实例必须通过prepare()方法来创建。 prepare()方法会创建一个 Looper 对象,并把它保存在静态变量mTreadLocal 中,一个线程多次调用**prepare()**会抛出异常。
静态变量sThreadLocal 该变量是一个ThreadLocal 类型,即线程本地存储区(TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的TLS区域。它通过将需要保存的对象和线程id关联在一起的方式实现了线程本地存储功能,作用就是将Looper类线程隔离,保证每个线程只能有一个Looper对象。
ThreadLocal.set(T value):
1 2 3 4 5 6 7 8 9 10 public void set (T value) { Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values == null ) { values = initializeValues(currentThread); } values.put(this , value); }
ThreadLocal.get():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public T get () { Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values != null ) { Object[] table = values.table; int index = hash & values.mask; if (this .reference == table[index]) { return (T) table[index + 1 ]; } } else { values = initializeValues(currentThread); } return (T) values.getAfterMiss(this ); }
loop() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public static void loop () { final Looper me = myLooper(); …… final MessageQueue queue = me.mQueue; …… for (;;) { Message msg = queue.next(); if (msg == null ) { return ; } …… msg.target.dispatchMessage(msg); …… msg.recycleUnchecked(); } }
loop()是一个静态方法,其中有一个无限的 for 循环,loop()方法会循环从消息队列 MessageQueue 中取出消息,然后分发出去。消息的分发是通过Message 中的target 变量完成的,这个变量是Handler 类型的,一个Looper 对象可以对应多个Handler 对象。
Message类 Message 是消息的载体。Message 设计成了Parelable 类的派生类,表明Message 可以通过binder 来跨进程发送。
1 public final class Message implements Parcelable
消息的类型
成员
类型
注解
what
int
消息类别
when
long
消息触发时间
arg1
int
参数1
arg2
int
参数2
obj
Object
消息内容
target
Handler
消息相应的地方
callback
Runnable
回调方法
obtain() 1 2 3 4 5 6 7 8 9 10 11 12 13 public static Message obtain () { synchronized (sPoolSync) { if (sPool != null ) { Message m = sPool; sPool = m.next; m.next = null ; m.flags = 0 ; sPoolSize--; return m; } } return new Message (); }
recycle() 1 2 3 4 5 6 7 8 9 public void recycle () { if (isInUse()) { if (gCheckRecycle) { throw new IllegalStateException ("This message cannot be recycled because it is still in use." ); } return ; } recycleUnchecked(); }
MessageQueue类 消息的构造
MessageQueue 对象的构造是调用本地方法nativeInit()完成的。 nativeInit()创建了一个本地 NativeMessageQueue ,它本质上是一个代理类。它把Java 层的调用转变为native 层Looper 类的函数调用,native 层的Looper 实现了一整套完整的消息处理机制。但是Java 层的Looper 类和native 层的Looper 类并没有直接的关系。MessageQueue 虽然使用了Native 层的Looper 类,但只用到了等待/唤醒机制 ,其余的如消息队列的实现还是在Java 层。
消息的处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 Message next () { final long ptr = mPtr; if (ptr == 0 ) { return null ; } int pendingIdleHandlerCount = -1 ; int nextPollTimeoutMillis = 0 ; for (;;) { if (nextPollTimeoutMillis != 0 ) { Binder.flushPendingCommands(); } nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this ) { final long now = SystemClock.uptimeMillis(); Message prevMsg = null ; Message msg = mMessages; if (msg != null && msg.target == null ) { do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null ) { if (now < msg.when ) { nextPollTimeoutMillis = (int ) Math.min(msg.when - now, Integer.MAX_VALUE); } else { mBlocked = false ; if (prevMsg != null ) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null ; if (DEBUG) Log.v(TAG, "Returning message: " + msg); msg.markInUse(); return msg; } } else { nextPollTimeoutMillis = -1 ; } if (mQuitting) { dispose(); return null ; } if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when )) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0 ) { mBlocked = true ; continue ; } if (mPendingIdleHandlers == null ) { mPendingIdleHandlers = new IdleHandler [Math.max(pendingIdleHandlerCount, 4 )]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } for (int i = 0 ; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null ; boolean keep = false ; try { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf(TAG, "IdleHandler threw exception" , t); } if (!keep) { synchronized (this ) { mIdleHandlers.remove(idler); } } } pendingIdleHandlerCount = 0 ; nextPollTimeoutMillis = 0 ; } }
向MessageQueue发消息 使用的是**enqueueMessage()**方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 boolean enqueueMessage (Message msg, long when ) { if (msg.target == null ) { throw new IllegalArgumentException ("Message must have a target." ); } if (msg.isInUse()) { throw new IllegalStateException (msg + " This message is already in use." ); } synchronized (this ) { if (mQuitting) { IllegalStateException e = new IllegalStateException ( msg.target + " sending message to a Handler on a dead thread" ); Log.w(TAG, e.getMessage(), e); msg.recycle(); return false ; } msg.markInUse(); msg.when = when ; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when ) { msg.next = p; mMessages = msg; needWake = mBlocked; } else { needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when ) { break ; } if (needWake && p.isAsynchronous()) { needWake = false ; } } msg.next = p; prev.next = msg; } if (needWake) { nativeWake(mPtr); } } return true ; }
enqueueMessage()方法插入消息时根据时间来排序,时间早的插在前面。消息队列的组织利用了 Message 类里面的next 指针形成一个从头指向尾的单向链表。插入时计算是否需要唤醒处理。**enqueueMessage()**方法会尽量避免唤醒处理线程,只有插入了一条马上要处理的消息,或者在暂停处理消息的情况下,有插入了“异步消息”的情况下才会去唤醒处理线程。其余的情况都是把消息放到队列的中部或尾部(时间未到)。如果前面还有消息没处理,这条消息就更不急于处理了。
Hander类 构造Handler 构造一个Handler 对象需要两个参数,线程的Looper 对象和消息的处理函数。Looper 是必须的,构造方法不指定则使用当前线程的Looper 对象。但是callback 不是必须的,可以用callback 实现对消息的集中处理,也可以把处理消息的callback 方法放在消息对象中。
无参构造 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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 ("" ); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
1 2 3 4 public static @Nullable Looper myLooper () { return sThreadLocal.get(); }
有参构造 1 2 3 4 5 6 7 8 9 10 public Handler (Looper looper) { this (looper, null , false ); } public Handler (Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }
send方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 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) { …… return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } public boolean sendMessageAtTime (Message msg, long uptimeMillis) { MessageQueue queue = mQueue; …… return enqueueMessage(queue, msg, uptimeMillis); } public final boolean sendMessageAtFrontOfQueue (Message msg) { MessageQueue queue = mQueue; …… return enqueueMessage(queue, msg, 0 ); }
所有的send 消息都调用了enqueueMessage()方法,最终调用了 MessageQueue 中的enqueueMessage()方法,就是把消息加入到了消息队列,并指定执行的时间。可以看到下面 queue.enqueueMessage()方法中除了 msg ,只有时间 。上述一系列的send 方法只是为了方便使用,可以从方法名中看出各自的使用情景。
1 2 3 4 5 6 7 private boolean enqueueMessage (MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this ; if (mAsynchronous) { msg.setAsynchronous(true ); } return queue.enqueueMessage(msg, uptimeMillis); }
post方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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); } public final boolean postAtFrontOfQueue (Runnable r) { return sendMessageAtFrontOfQueue(getPostMessage(r)); }
从代码上看这些post 方法的实现也是用send ,只是多了Runnable 对象,然后调用getPostMessage()方法获取一个 Message 对象来发送。
1 2 3 4 5 6 7 8 9 10 11 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; }
dispatchMessage()方法 1 2 3 4 5 6 7 8 9 10 11 12 public void dispatchMessage (Message msg) { if (msg.callback != null ) { handleCallback(msg); } else { if (mCallback != null ) { if (mCallback.handleMessage(msg)) { return ; } } handleMessage(msg); } }
从上面可以看到消息分发的优先级:
Message的回调方法:message.callback;
Handler的回调方法:Handler.mCallback.handleMessage(msg);
Handler的默认方法:Handler.handleMessage(msg)。
dispatchMessage()方法的调用在Looper类中的loop()方法 :
1 2 3 4 5 6 7 8 public static void loop () { for (;;) { …… msg.target.dispatchMessage(msg); …… msg.recycleUnchecked(); } }
流程图
参考文献 [1] http://gityuan.com/2015/12/26/handler-message-framework/
[2] http://yuqiangqiang.com/2014/11/08/android基础总结/9-android下的Handler机制/
[3] http://www.kancloud.cn/digest/androidfrom-0/144443
[4] https://developer.android.com/training/multiple-threads/communicate-ui.html
[5] https://blog.nikitaog.me/2014/10/11/android-looper-handler-handlerthread-i/
[6] http://www.cnblogs.com/codingmyworld/archive/2011/09/14/2174255.html#!comments
[7] http://www.jianshu.com/p/02962454adf7
[8] http://www.feeyan.cn/?p=17
[9] http://anany.me/2015/04/12/handler/
[10] http://gityuan.com/2015/12/27/handler-message-native/#nativepollonce
[11] https://www.zhihu.com/question/34652589