Roly's Blog

Whatever will be, will be, the future's not ours to see.

0%

Android消息机制

​ 消息驱动模式是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 : 发送和处理消息(MessageRunnable对象),与一个线程的MessageQueue关联。一个Handler实例与一个线程(包括线程的消息队列)绑定。当一个Handler实例被创建时,该实例与创建它的线程/线程的消息队列 绑定到一起,然后向该消息队列发送MessageRunnable,并且当发送的MessageRunnable从消息队列返回时处理它们。

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对象
values = initializeValues(currentThread);
}
//保存数据value到当前线程this
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对象
values = initializeValues(currentThread);
}
return (T) values.getAfterMiss(this); //从目标线程存储区没有查询是则返回null
}

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();//获取本地存储区的Looper对象
……
final MessageQueue queue = me.mQueue;//消息队列
……
for (;;) {
Message msg = queue.next(); // might block,这里可能阻塞
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() {//从消息池中返回一个新的Message实例,避免申请太多的Message
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();
}

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层的调用转变为nativeLooper类的函数调用,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; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//调用本地方法等待nextPollTimeoutMillis秒,-1表示永远阻塞
nativePollOnce(ptr, nextPollTimeoutMillis);
//针对this对象同步,只要next方法没退出,再调用本对象的任何方法都将导致调用线程挂起
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. 忽略普通消息,查找下一条异步消息
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 {
// Got a message.
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 {
// No more messages.
nextPollTimeoutMillis = -1;
}
//如果退出标志设置了,销毁native对象
if (mQuitting) {
dispose();
return null;
}
//检查是否安装了idle handler
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
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;
//如果又idle handler ,循环继续,而不是阻塞
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) {//如果消息的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) {//用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;//p指向消息队列头
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg; //把消息插到队列头
needWake = mBlocked;//这时如果处理线程阻塞了,则需要唤醒
} else {
//如果设置了“SyncBarrier”,只有插入了“异步消息”才需要唤醒
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; // invariant: p == prev.next
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) {
//匿名类、内部类或本地类都必须申明为static,否则会警告可能出现内存泄露
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(); //从sThreadLocal中获取Looper对象,下面Looper中的函数可以看到
if (mLooper == null) {
throw new RuntimeException("");
}
mQueue = mLooper.mQueue; //消息队列,来自Looper对象
mCallback = callback; //回调方法
mAsynchronous = async; //设置消息是否为异步处理方式
}
1
2
3
4
//Looper类中的方法,见2.3
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;//这里callback被携带在message中,参见3.1
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);//message中的callback
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {//Handler构造时,指定的callback
return;
}
}
handleMessage(msg);//Handler默认方法
}
}

从上面可以看到消息分发的优先级:

  1. Message的回调方法:message.callback;
  2. Handler的回调方法:Handler.mCallback.handleMessage(msg);
  3. Handler的默认方法:Handler.handleMessage(msg)。

dispatchMessage()方法的调用在Looper类中的loop()方法

1
2
3
4
5
6
7
8
public static void loop() {//见2.4
for (;;) {
……
msg.target.dispatchMessage(msg);//消息分发
……
msg.recycleUnchecked();//消息回收
}
}

流程图

Android消息机制

参考文献

[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