android中处理一些费时的操作需要单独启动一个子线程去处理。子线程处理完毕将结果通知给UI主线程更新UI界面。 子线程与UI主线程的通信在android中使用了消息机制来完成,那么是怎么完成的呢?这就和handler机制的原理(android中线程间通信的原理,而不是进程间通信), 简而言之,就是需要两样古老的东西,消息队列、轮询。也就是说,主线程起来以后有一个消息队列,同时和该队列配对的有一个轮询, 而子线程有这个消息队列的引用,那这样,子线程处理完以后就会向主线程的消息队列发消息,主线程轮询自己的队列,发现有未处理的消息就进行处理。 这就是handler的机制。
looper对象拥有message queue,并且负责从message queue中取出消息给handler来处理。同时handler又负责发送message给looper,由looper把message添加到message queue尾部。 handler和looper是来联系在一起的。多个message可以指向同一个handler,多个handler也可以指向同一个looper。
Handler
消息的处理者,handler负责将需要传递的信息封装成Message,通过调用handler对象的obtainMessage()来实现。将消息传递给Looper, 这是通过handler对象的sendMessage()来实现的。继而由Looper将Message放入MessageQueue中。当Looper对象看到MessageQueue中含有Message, 就将其分发出去。该handler对象收到该消息后,调用相应的handler对象的handleMessage()方法对其进行处理。
Handler一些特点:handler可以分发Message对象和Runnable对象到主线程中,每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程), 它有两个作用: (1)安排消息或Runnable在某个主线程中某个地方执行。(2)安排一个动作在不同的线程中执行。
Message
消息对象,Message Queue中的存放的对象。一个Message Queue中包含多个Message。Message实例对象的取得, 通常使用Message类里的静态方法obtain(),该方法有多个重载版本可供选择;它的创建并不一定是直接创建一个新的实例, 而是先从Message Pool(消息池)中看有没有可用的Message实例,存在则直接取出返回这个实例。如果Message Pool中没有可用的Message实例, 则才用给定的参数创建一个Message对象。调用removeMessages()时,将Message从Message Queue中删除,同时放入到Message Pool中。 除了上面这种方式,也可以通过Handler对象的obtainMessage()获取一个Message实例。
MessageQueue
消息队列,存放消息的地方。每一个线程最多只可以拥有一个MessageQueue数据结构。创建一个线程的时候,并不会自动创建其MessageQueue。 通常使用一个Looper对象对该线程的MessageQueue进行管理。主线程创建时,会创建一个默认的Looper对象,而Looper对象的创建, 将自动创建一个Message Queue。其他非主线程,不会自动创建Looper,要需要的时候,通过调用Looper的prepare函数来实现。
Looper
Looper是MessageQueue的管理者。每一个MessageQueue都不能脱离Looper而存在,Looper对象的创建是通过prepare函数来实现的。 同时每一个Looper对象和一个线程关联。通过调用Looper.myLooper()可以获得当前线程的Looper对象 创建一个Looper对象时, 会同时创建一个MessageQueue对象。除了主线程有默认的Looper,其他线程默认是没有MessageQueue对象的,所以,不能接受Message。 如需要接受,自己定义一个Looper对象(通过prepare函数),这样该线程就有了自己的Looper对象和MessageQueue数据结构了,而且一个线程只能有一个looper。 调用完prepare以后,此线程就成为了所谓的LooperThread,若在当前LooperThread中创建Handler对象,那么此Handler会自动关联到当前线程的looper对象,也就是拥有looper的引用。 Looper从MessageQueue中取出Message然后,交由Handler的handleMessage进行处理。处理完成后,调用Message.recycle()将其放入Message Pool中。
源码解析
handler其构造函数:
[代码]java代码:
?
|
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
public Handler(boolean async) {
this(null, async);
}
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;
}
|
构造方法中无参构造和没有传递looper的构造最终调用了public Handler(Callback callback, boolean async); 在这个方法中获得当前线程的looper,再使用这个looper获得looper上的message queue。
而如果构造中传递了looper,则调用 public Handler(Looper looper, Callback callback, boolean async), 用传递进来的looper代替默认的looper,然后再同样的初始化mQueue,mCallback,mAsynchronous。
先看mLooper = Looper.myLooper();这一句发生了什么:
[代码]java代码:
?
|
1
2
3
|
public static Looper myLooper() {
return sThreadLocal.get();
}
|
可以看到,该方法返回一个sThreadLocal对象中保存的Looper。如果尚未在当前线程上运行过Looper.prepare()的话,myLooper会返回null。 接下来看看Looper.prepare()的实现:
[代码]java代码:
?
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
public static void prepare() {
prepare(true);
}
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对象,并将其保存在sThreadLocal中。在注释中说明了prepare()要在loop()之前调用,最后 调用quit()。接下来看一下Looper的构造函数。
[代码]java代码:
?
|
1
2
3
4
|
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
|
调用完Looper.prepare()后,需调用Looper.loop()才能使消息循环运作起来,其源码如下所示:
[代码]java代码:
?
|
01
02
03
04
05
06
07
08
09
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
|
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
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);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println(" + 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();
}
}
|
在loop()主要干了四件事:
1.调用Looper me = myLooper()取出looper对象。
2.调用MessageQueue queue = me.mQueue; 取出looper绑定的message queue。
3.死循环调用Message msg = queue.next();在message queue中取数据,若msg为null就不执行下面的分发,跳出死循环。 这里为什么敢直接跳出循环?因为上一行的queue.next()里也是一个循环,这个循环实现很巧妙,只有遇到message时才取出,否则阻塞。 一旦queue.next()里的循环阻塞了,外面的for循环也阻塞了,避免了空循环浪费资源。queue.next()里的for循环也不是一直做空循环的, 它会根据message里的when字段(postDelay设置的延迟)来计算时间,到时间了才会开始取,其他时间都是阻塞状态。
4.在上面的循环中若msg不为null,调用msg.target.dispatchMessage(msg); 分发message到指定的target handler。
[代码]java代码:
?
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
|
分发之后就执行了mCallback中的回调,这个回调就是我们自己覆写的方法public void handleMessage(Message msg)。
从上面代码也可以看出,轮询器在for (;;){}死循环代码块中不断的执行,通过queue.next();从MessageQueue中取出一个Message, 当msg不为空时,执行msg.target.dispatchMessage(msg);(实际上最终是调用到了Handler的dispatchMessage方法去拦截消息)
在Message中的源码中,target就是当前线程的Handler对象,msg的成员变量target是在发送消息的时候设置好的,一般就通过哪个Handler 来发送消息,就通过哪个Handler来处理消息。
接下来看一下Message类:
[代码]java代码:
?
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
public final class Message implements Parcelable {
public int what;
public int arg1;
public int arg2;
public Object obj;
...
int flags;
long when;
Bundle data;
Handler target;
Runnable callback;
Message next;
private static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
}
|
Message中有一个静态类型的Message对象,叫做sPool,同时还有一个叫做next的Message对象,这个应该是指向队列中下一个message的引用。 当我们调用Message.obtain()时,返回了一个Message对象。Message对象使用完毕后,调用recycle()方法将其回收。其中obtain方法的代码如下所示:
[代码]java代码:
?
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
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();
}
|
可以看到,obtain方法被调用时,首先检测sPool对象是否为空,若不为空将其当做新的message对象返回,并指向message对象的next属性, sPoolSize自减。可以看出message对象通过next属性串成了一个链表,sPool为“头指针”。再来看看recycle方法的实现。
[代码]java代码:
?
|
01
02
03
04
05
06
07
08
09
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
|
public void recycle() {
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
}
return;
}
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 = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
|
如果message对象不是处于正在被使用的状态,则会被回收。其属性全部恢复到原始状态后,放在了链表的头部。sPool对象“指向”它,sPoolSize自增。 可以看出,通过obtain和recycle方法可以重用message对象。通过操作next、sPoolSync、sPool、sPoolSize这四个属性,实现了一个类似栈的对象池。
下面看看msg对象是如何放到消息队列里面的,通常来说,我们通过Handler的sendMessage(msg)方法来发送消息,其源码如下所示:
[代码]java代码:
?
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
...
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis
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);
}
...
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
|
可知sendMessage最终会调用queue.enqueueMessage(msg, uptimeMillis)将msg对象保存至message queue中,uptimeMillis表示msg执行回调的时刻。 我们来看一下MessageQueue类的enqueueMessage方法:
[代码]java代码:
?
|
01
02
03
04
05
06
07
08
09
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
|
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("MessageQueue", e.getMessage(), e);
msg.recycle();
return false;
}
// 1.设置当前msg的状态
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
// 2.检测当前头指针是否为空(队列为空)或者没有设置when 或者设置的when比头指针的when要前
if (p == null || when == 0 || when
// 3. 插入队列头部,并且唤醒线程处理msg
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
//4. 几种情况要唤醒线程处理消息:1)队列是堵塞的 2)barrier,头部结点无target 3)当前msg是堵塞的
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
// 5. 将当前msg插入第一个比其when值大的结点前。
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
|
结合注释,我们可以了解到msg push到queue中时,queue的状态的变化和处理队列的逻辑。 前文中Looper对象的loop方法中:
[代码]java代码:
?
|
01
02
03
04
05
06
07
08
09
10
11
|
for (;;) {
...
Message msg = queue.next(); // 3. 堵塞式在message queue中取数据
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
msg.target.dispatchMessage(msg); 4. 分发message到指定的target handler
...
}
|
可以看出,message queue的next方法被调用时,可能会发生堵塞。我们来看一看message queue的next方法:
[代码]java代码:
?
|
01
02
03
04
05
06
07
08
09
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
|
Message next() {
// 1. 判断当前loop是否已经使用过,下文会解释这个mPtr
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
// 2. 进入死循环,直到获取到合法的msg对象为止。
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands(); // 这个是什么?
}
// 3. 进入等待,nextPollTimeoutMillis为等待超时值
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// 4. 获取下一个msg
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// 当前节点为barrier,所以要找到第一个asynchronous节点
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now
// 当前队列里最早的节点比当前时间还要晚,所以要进入堵塞状态,超时值为nextPollTimeoutMillis
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 (false) Log.v("MessageQueue", "Returning message: " + msg);
return msg;
}
} else {
// 头结点指向null
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// 5. 如果当前状态为idle(就绪),则进入idle handle的代码块
// 进入idle的情况有:队列为空;队列头元素blocking;
if (pendingIdleHandlerCount
&& (mMessages == null || now
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount
// 6. 本轮唤醒(next被调用)时没处理任何东西,故再次进入等待。
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// 在一次next调用中,这个代码块只会执行一次
for (int i = 0; i
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
// 如果返回true,则idler被保留,下次next的idle时会被调用。
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf("MessageQueue", "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
|
代码执行流程见注释。其中IdleHandler是一个接口:
[代码]java代码:
?
|
1
2
3
|
public static interface IdleHandler {
boolean queueIdle();
}
|
IdleHandler提供了一个在MessageQueue进入idle时的一个hook point。更多时与barrier机制一起使用,使message queue遇到barrier时产生一个回调。
总结
前面涉及到的几个主要的类Handler、Looper、MessageQueue和Message的关系如下所述:
1.Handler负责将Looper绑定到线程,初始化Looper和提供对外API。 2.Looper负责消息循环和操作MessageQueue对象。 3.MessageQueue实现了一个堵塞队列。 4.Message是一次业务中所有参数的载体。
原文链接:http://www.apkbus.com/blog-705730-61239.html