转自:http://solarex.github.io/blog/2015/09/22/android-message-handling-mechanism/
Android is a message driven, message driven several elements:
- The message says: Message
- Message queue: MessageQueue
- The news cycle, remove the message processing for circulation: Looper
- Message processing, message loop out messages from the message queue should be carried out after the processing of messages: Handler
Usually we use most often is Message
and Handler
, if you use HandlerThread
or similar HandlerThread
things may come into contact with Looper
, while MessageQueue
is used inside Looper
, for the standard SDK, we are unable to instantiate and use (constructor is package visibility). We usually come into contact with Looper
,Message
, Handler
are realized by JAVA, Android for Linux based systems, the bottom with a C, C++, and NDK exist, how could the message driven model only exists in the JAVA layer, in fact, there are corresponding to the Java layer such as Looper
, MessageQueue
in the Native layer.
Android是消息驱动的,实现消息驱动有几个要素:
- 消息的表示:Message
- 消息队列:MessageQueue
- 消息循环,用于循环取出消息进行处理:Looper
- 消息处理,消息循环从消息队列中取出消息后要对消息进行处理:Handler
平时我们最常使用的就是Message与Handler了,如果使用过HandlerThread或者自己实现类似HandlerThread的东西可能还会接触到Looper,而MessageQueue是Looper内部使用的,对于标准的SDK,我们是无法实例化并使用的(构造函数是包可见性)。
我们平时接触到的Looper、Message、Handler都是用JAVA实现的,Android做为基于Linux的系统,底层用C、C++实现的,而且还有NDK的存在,消息驱动的模型怎么可能只存在于JAVA层,实际上,在Native层存在与Java层对应的类如Looper、MessageQueue等。
Initialization message queue
First to see if a thread to achieve the message loop should do, taking HandlerThread as an example:
首先来看一下如果一个线程想实现消息循环应该怎么做,以HandlerThread为例:
1
2
3
4
5
6
7
8
9
10
11
12
|
|
In the red mark of the two, first call prepare to initialize the MessageQueue
and Looper
, and then call the loop enter the message loop. First look at the Looper.prepare
.
主要是红色标明的两句,首先调用prepare初始化MessageQueue与Looper,然后调用loop进入消息循环。先看一下Looper.prepare。
1
2
3
4
5
6
7
8
9
10
|
|
Overloaded functions, quitAllowed
default to true, from the name can be seen is whether the message loop can exit, the default is to exit, the Main thread (UI thread) initialization message loop is called prepareMainLooper
, pass is false. The use of ThreadLocal
, each thread can initialize a Looper
.
Look at the Looper
in the initialization did:
重载函数,quitAllowed默认为true,从名字可以看出来就是消息循环是否可以退出,默认是可退出的,Main线程(UI线程)初始化消息循环时会调用prepareMainLooper,传进去的是false。使用了ThreadLocal,每个线程可以初始化一个Looper。
再来看一下Looper在初始化时都做了什么:
1
2
3
4
5
6
7
8
9
10
|
|
In the Looper
initialization, a MessageQueue
object created saved in the mQueue member. The MessageQueue
constructor is package visibility, so we cannot be used directly, while the MessageQueue
initialization is called thenativeInit
, which is a Native method:
在Looper初始化时,新建了一个MessageQueue的对象保存了在成员mQueue中。MessageQueue的构造函数是包可见性,所以我们是无法直接使用的,在MessageQueue初始化的时候调用了nativeInit,这是一个Native方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
|
In nativeInit
, the new object of a Native layer MessageQueue
, and the address stored in the Java layer of theMessageQueue
member of the mPtr
, there are a lot of implementation of Android, a class has been implemented in Java layer and Native layer, the GetFieldID
and SetIntField
JNI saved Native layer class an address to the Java layer for an instance of the class mPtr
members, such as Parcel
.
Then the realization of NativeMessageQueue
:
在nativeInit中,new了一个Native层的MessageQueue的对象,并将其地址保存在了Java层MessageQueue的成员mPtr中,Android中有好多这样的实现,一个类在Java层与Native层都有实现,通过JNI的GetFieldID与SetIntField把Native层的类的实例地址保存到Java层类的实例的mPtr成员中,比如Parcel。
再看NativeMessageQueue的实现:
1
2
3
4
5
6
7
|
|
Gets a Native layer of the Looper
object in the constructor of the NativeMessageQueue
, Native layer Looper also use thread local storage, note that new Looper
introduced parameter false.
在NativeMessageQueue的构造函数中获得了一个Native层的Looper对象,Native层的Looper也使用了线程本地存储,注意new Looper时传入了参数false。
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
|
|
Native layer in Looper
using epoll
. Initializes a pipeline, mWakeWritePipeFd
and mWakeReadPipeFd
were preserved to write and read end of pipe end, and monitor the read end of the EPOLLIN event. Note the initializer list of values, the value of mAllowNonCallbacks
for false
.
What is mAllowNonCallback
? The use of epoll
to monitor mWakeReadPipeFd
events? In fact, Native Looper
can not only monitor the descriptors, Looper
also provides the addFd
method:
Native层的Looper使用了epoll。初始化了一个管道,用mWakeWritePipeFd与mWakeReadPipeFd分别保存了管道的写端与读端,并监听了读端的EPOLLIN事件。注意下初始化列表的值,mAllowNonCallbacks的值为false。
mAllowNonCallback是做什么的?使用epoll仅为了监听mWakeReadPipeFd的事件?其实Native Looper不仅可以监听这一个描述符,Looper还提供了addFd方法:
1
2
|
|
fd
said to monitor descriptor. ident
said to monitor event identification, Value must be >=0 or be ALOOPER_POLL_BACK(-2), event
said to monitor events, callback
is a callback function when the event occurs, This is the role of mAllowNonCallbacks
, When the mAllowNonCallbacks
is true allows callback to NULL, ident
inpollOnce
as a result of return, Otherwise, do not allow the callback is empty, When the callback is not NULL, The value of ident will be ignored. Or just look at the code easy to understand:
fd表示要监听的描述符。ident表示要监听的事件的标识,值必须>=0或者为ALOOPER_POLL_CALLBACK(-2),event表示要监听的事件,callback是事件发生时的回调函数,mAllowNonCallbacks的作用就在于此,当mAllowNonCallbacks为true时允许callback为NULL,在pollOnce中ident作为结果返回,否则不允许callback为空,当callback不为NULL时,ident的值会被忽略。还是直接看代码方便理解:
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
|
|