Android 消息机制
Android 消息机制
记忆点:
消息机制 -> Handler更新UI -> 主要相关类:
- Message:需要传递的信息,可以传递数据
- MessageQueue:消息队列,但不是队列,内部实现为一个单链表的数据结构,因为单链表在插入和删除上比较有优势。主要功能:向消息池投递消息
MessageQueue.enqueueMessage
和取走消息池的消息MessageQueue.next
- Handler:消息辅助类,主要功能:向消息池发送各种消息事件
handler.sendMessage
和处理响应消息事件handler.handleMessage
- Looper:不断循环执行
Looper.loop
,从 MessageQueue 中读取消息,按分发机制将消息分发给目标处者
-> 运行流程:
在子线程执行完耗时操作,当Handler发送消息时,将会调用
MessageQueue.enqueueMessage
,向消息队列中添加消息。当通过Looper.loop
开启循环后,会不断从线程池中读取消息,即调用MessageQueue.next
,然后调用目标 Handler (即发送该消息的 Handler)的dispatchMessage
方法传递消息,然后返回到 Handler 所在线程,目标 Handler 收到消息,调用handleMessage
方法,接收消息,处理消息。
-> MessageQueue,Handler 和 Looper 三者之间的关系:
一个线程一个 Looper,可以有多个 Handler,Looper 中维护一个 MessageQueue 来维护消息队列,消息队列中的 Message 可以来自不同 Handler。
消息机制源码解析:
Looper
初始化:default:prepare(true)
,布尔值表示的是这个 Looper 是否可以退出。还限制不能重复创建 Looper。
开启 Looper:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public static void loop(){
final Looper me = myLooper(); //获取TLS存储的Looper对象
if(me == null){
throw new RuntimeExceprion("No Looper; Looper.prepare() wasn't called on this thread");
}
final MesssageQueue queue = me.mQueue; //Looper中对象中的消息队列
...
for(;;){
Message msg = queue.next(); //可能会阻塞,因为next()方法可能会无限循环
... //判空、日志处理
msg.target.dispatchMessage(msg); // msg.target:目标Handler
...
msg.recycleUnchecked();
}
}
创建 Handler:
1 | public Handler(){ |
发送消息:
Handler的send
或post
方式最终都是调用了sendMessageAtTime()
。内部大致流程:sendMessageAtTime(msg, uptimeMillis)
->enqueueMessage(queue, msg, uptimeMillis)
->queue.enqueueMessage(msg, uptimeMillis)
其中 queue 是以 mQueue 赋值的局部变量,而 mQueue 是消息队列,是从 Looper 中获取的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// MessageQueue enqueueMessage() 方法的具体逻辑
boolean enqueueMessage(Message msg, long when){
...// 判空、msg是否已被使用
synchronized(this){
if(mQuitting){ //正在退出时,回收msg,加入到消息池
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if(p == null || when == 0 || when < p.when){
//p为null(代表MessageQueue没有消息)或者msg的触发时间是队列中最早的
msg.next = p;
mMessages = msg;
needWake = mBlocked;
}else{
// 一般地,不需要唤醒事件队列,除非消息队头存在barrier,并且同时Message是队列中最早的异步消息
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for(;;){
// 将消息按触发时间顺序插入到MessageQueue
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;
}
获取消息
发送消息之后,在 MessageQueue 维护了消息队列,然后再 Looper 中通过loop()
不断地获取消息。loop()
->queue.next()
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
52Messsage next(){
final long ptr = mPtr;
if(ptr == 0){ //当消息循环已经退出,则直接返回
return null;
}
int pendingIdleHandlerCount = -1; //循环迭代的首次为-1
int nextPollTimeoutMillis = 0;
for(;;){
if(nextPollTimeoutMillis != 0){
Binder.flushPendingConmmands();
}
//阻塞操作,当等待nextPollTimeoutMillis时长,或者消息队列被唤醒,都会返回
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this){
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages; // mMessages保存链表的第一个元素
if(msg != null && msg.target == null){
//当消息Handler为null时,查询MessageQueue中的下一条异步消息msg,为空则退出循环
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;
//设置消息的使用状态,即flages |= FLAG_IN_USE
msg.markInUse();
return msg;
}
}else {
nextPollTimeoutMillis = -1;
}
if(mQuitting){
dispose();
return null;
}
}
...
}
}
分发消息
在loop()
方法中,获取到下一条消息后,执行msg.target.dispatchMessage(msg)
,来分发消息到目标 Handler。1
2
3
4
5
6
7
8
9
10
11
12
13public void dispatchMessage(Message msg){
//消息分发的优先级
if(msg.callback != null){
handleCallback(msg);
}else {
if(mCallback != null){
if(mCallback.handleMessage(msg)){
return;
}
}
handleMessage(msg); //很多情况下分发消息的处理方法为这个
}
}
图解
其他知识
- ThreaLocal:每并不是一个 Thread,而是 Thread 的局部变量。当使用 ThreadLocal 维护变量时,ThreadLocal 为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。从线程的角度看,目标变量就象是线程的本地变量,这也是类名中 Local 所要表达的意思
- Android 中主线程为什么不会被 Looper.loop() 死循环卡死?——保证程序一直执行,thread.attach(false);创建 Binder 通道(新线程,接收 AMS 发送来的事件);承载 ActivityThread 的主线程就是由 Zygote fork 而创建的进程;不耗 CPU 资源,涉及到 pipe/epoll 机制;Activity 的内部类 H 继承于 Handler,Activity 的生命周期都是依靠主线程的 Looper.loop,当收到不同的 Message 时采取相应的措施。