android消息机制

描述:

消息机制可以说是4个类的关系,分别是

  • Handler
  • Looper
  • MessageQueue
  • Message

其中流程是这样子的,开启一个消息循环,每循环一次,便从消息队列中取出一个消息,然后交给相应的Handler来处理。
而消息循环的具体实现就是一个LooperLooper内部持有了一个消息队列, 我们要用Looperprepare()方法在当前线程中创建唯一的Looper对象,其中,Looper内部持有一个消息 队列,并

在ActivityThread的main()函数中,即启动UI线程,便是开启一个消息循环。 在UI线程中,确保有且仅有一个消息循环,之后,所有的与UI相关的操作,都会通过Hanlder以发消息的形式先放入MessageQueueLooper通过执行一个循环,不断取出队列的消息Message, 再将该消息交给对应的Handler来处理。

有了这个消息机制,其他线程(包括UI线程本身),对应UI有什么操作想法,不再能直接就修改,而是将想法包装成消息,放到消息队列中,再一一处理。 通过这样的机制,才能保证UI的运行正常。试想,若是线程A,B分别要在屏幕同一位置画一个鸡,鸭,若让A,B的请求同时执行,结果就是鸡鸭都画不成了, 可知,对于不同的线程的请求,必须要有个先后。或是说,线程A可能要画3秒钟,再让B画两秒钟,通过消息,就很容易让这些任务同步。可能,这两个例子有点狭隘了。

源码跟踪

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
main(){
Looper.prepareMainLooper() //准备一个唯一mainLooper

Looper.loop() //启动消息循环
}

//Looper.prepareMainLooper
prepare(false)
sychronized(Looper.class){
if(sMainLooper!=null){ //确保只有一个主循环
throw IllegalException()
}
sMainLooper=mLooper()
}

//prepare(false)
private static void prepare(boolean quitAllowed) { //使用ThreadLocal确保每个线程只有一个Looper
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
//Looper()
private Looper(boolean quitAllowed) { //创建一个消息队列
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}

//启动循环
public static void loop() {
final Looper me = myLooper();
//额外话,为什么很多变量不直接用类的成员变量,而是新创建一个局部final变量来使用?
//以为Java中变量都是可变的,若是在操作中变量指向改变了,逻辑就没法确定了,所以使用一个本地的final变量指向它
for(;;){
...
//从消息队列获取消息,(这里的可能会阻塞,即执行到这里会等待,与Socket中Server等待客户端连接相似,具体是什么原理有待研究...)
Message msg = queue.next(); // might block

//使用消息中对象target,来处理该消息,target就是handler
msg.target.dispatchMessage(msg);

//消息回收处理
//目的为了避免创建过多的对象,引发GC
msg.recycleUnchecked();
}
}
//recycleUnchecked
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 = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;

synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool; //可以看到,这里的Message本身就作为一个列表节点,且这里使用头插法将消息放回池子中
sPool = this;
sPoolSize++;
}
}
}

//msg.target.dispatchMessage(msg);
//可以看到,消息从队列拿出来后,根据msg和handler会有不同处理方式
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) { //若是消息指定了callback了,即handler通过post*(r)方法来发的
handleCallback(msg); 
} else {
if (mCallback != null) { //若是handler有callback,优先使用handler的callbak来处理
if (mCallback.handleMessage(msg)) { //这里还要根据callback中的返回值,来判断是否还要继续调用Handler的handerMessage()方法
return;
}
}
handleMessage(msg); //这里是我们通常的写法,在handlerMessage中处理消息
}
}

//Hanlder的创建,以及发送消息

//使用内部类来创建
@SuppressLint("HandlerLeak")
Handler handler1 = new Handler() {
@Override
public void handleMessage(Message msg) {

}
};

//传入callback来创建
Handler handler2 = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
return false;
}
});

hanlder.send*()
hanlder.post*()
//通过handler来发送消息,无论是send*()还是post*(),最终都是调用了
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; //
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis); //入队列
}

额外补充

Handler中的AndroidLeak
ThreadLocal