手记

Android应用程序消息处理机制

原文链接:http://www.apkbus.com/blog-705730-61240.html


Android的消息处理机制主要分为四个部分:

·         创建消息队列

·         消息循环

·         消息发送

·         消息处理

主要涉及三个类:

·         MessageQueue

·         Looper

·         Handler

Android应用程序每启动一个线程,都为其创建一个消息队列,然后进入到一个无限循环之中。然后不断检查队列中是否有新消息需要处理。如果没有,线程就会进入睡眠状态,反之会对消息进行分发处理。

下面根据上面所说的进行详述。

创建消息队列

整个创建过程涉及到两个类:MessageQueue 和 Looper。它们在C++层有两个对应的类:NativeMessageQueue和Looper。其关系如下图所示:

1

2

3

4

5

6

7

8

9

10

11

12

      +------------+       +------+

      |MessageQueue+----^+Looper|

      +-----+------+       +------+

            |                    

            |                    

            |                    

+-----------+------+       +------+

|NativeMessageQueue+^----+Looper|

+------------------+       +------+

 

        A----^B表示B中保存A的引用

 

创建过程如下所示:

1.       Looper的prepare或者prepareMainLooper静态方法被调用,将一个Looper对象保存在ThreadLocal里面。

2.      Looper对象的初始化方法里,首先会新建一个MessageQueue对象。

3.      MessageQueue对象的初始化方法通过JNI初始化C++层的NativeMessageQueue对象。

4.      NativeMessageQueue对象在创建过程中,会初始化一个C++层的Looper对象。

5.      C++层的Looper对象在创建的过程中,会在内部创建一个管道(pipe),并将这个管道的读写fd都保存在mWakeReadPipeFd和mWakeWritePipeFd中。
然后新建一个epoll实例,并将两个fd注册进去。

6.      利用epoll的机制,可以做到当管道没有消息时,线程睡眠在读端的fd上,当其他线程往管道写数据时,本线程便会被唤醒以进行消息处理。

消息循环

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

          +------+    +------------+  +------------------+  +--------------+                    

          |Looper|    |MessageQueue|  |NativeMessageQueue|  |Looper(Native)|                    

          +--+---+    +------+-----+  +---------+--------+  +-------+------+                    

               |                 |                  |                     |                            

               |                 |                  |                     |                            

+-------------------------------------------------------------------------------+                

|[msg   loop]  |     next()      |                  |                     |             |                

|            +------------>  |                  |                     |             |                

|            |                 |                  |                     |             |                

|            |                 |                  |                     |             |                

|            |                 | nativePollOnce() |                     |             |                

|            |                 |    pollOnce()    |                     |             |                

|            |                 +----------------> |                     |             |                

|            |                 |                  |                     |             |              

|            |                 |                  |                     |             |                

|            |                 |                  |                     |             |                

|            |                 |                  |                     |             |                

|            |                 |                  |       pollOnce()    |             |                

|            |                 |                  +-----------------> |             |                

|            |                 |                  |                     |             |                

|            |                 |                  |                     | epoll_wait()              

|            |                 |                  |                     +--------+  |                

|            |                 |                  |                     |        |  |                

|            |                 |                  |                     |        |  |                

|            |                 |                  |                     | <------+  |                

|            |                 |                  |                     | awoken()  |                

|            +                 +                  +                     +             |                

|                                                                                 |                

|                                                                                 |                

+-------------------------------------------------------------------------------+                

 

1.       首先通过调用Looper的loop方法开始消息监听。loop方法里会调用MessageQueue的next方法。next方法会堵塞线程直到有消息到来为止。

2.      next方法通过调用nativePollOnce方法来监听事件。next方法内部逻辑如下所示(简化):
a. 进入死循环,以参数timout=0调用nativePollOnce方法。
b. 如果消息队列中有消息,nativePollOnce方法会将消息保存在mMessage成员中。nativePollOnce方法返回后立刻检查mMessage成员是否为空。
c. 如果mMessage不为空,那么检查它指定的运行时间。如果比当前时间要前,那么马上返回这个mMessage,否则设置timeout为两者之差,进入下一次循环。
d. 如果mMessage为空,那么设置timeout为-1,即下次循环nativePollOnce永久堵塞。

3.      nativePollOnce方法内部利用epoll机制在之前建立的管道上等待数据写入。接收到数据后马上读取并返回结果。

消息发送

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

          +-------+       +------------+     +------------------+     +--------------+                        

          |Handler|       |MessageQueue|     |NativeMessageQueue|     |Looper(Native)|                        

          +--+----+       +-----+------+     +---------+--------+     +-------+------+                        

               |                |                    |                    |                                

               |                |                    |                    |                                

sendMessage()|                |                    |                    |                                

+----------> |                |                    |                    |                                

               |                |                    |                    |                                

               |enqueueMessage()|                    |                    |                                

               +--------------> |                    |                    |                                

               |                |                    |                    |                                

               |                |                    |                    |                                

               |                |                    |                    |                                

               |                |  nativeWake()      |                    |                                

               |                |    wake()          |                    |                                

               |                +------------------> |                    |                                

               |                |                    |                    |                                

               |                |                    |    wake()          |                                

               |                |                    +------------------> |                                

               |                |                    |                    |                                

               |                |                    |                    |                                

               |                |                    |                    |write(mWakeWritePipeFd, "W", 1)

               |                |                    |                    |                                

               |                |                    |                    |                                

               |                |                    |                    |                                

               |                |                    |                    |                                

               |                |                    |                    |                                

               +                +                    +                    +                                

 

消息发送过程主要由Handler对象来驱动。

1.       Handler对象在创建时会保存当前线程的looper和MessageQueue,如果传入Callback的话也会保存起来。

2.      用户调用handler对象的sendMessage方法,传入msg对象。handler通过调用MessageQueue的enqueueMessage方法将消息压入MessageQueue。

3.      enqueueMessage方法会将传入的消息对象根据触发时间(when)插入到message queue中。然后判断是否要唤醒等待中的队列。
a. 如果插在队列中间。说明该消息不需要马上处理,不需要由这个消息来唤醒队列。
b. 如果插在队列头部(或者when=0),则表明要马上处理这个消息。如果当前队列正在堵塞,则需要唤醒它进行处理。

4.      如果需要唤醒队列,则通过nativeWake方法,往前面提到的管道中写入一个”W”字符,令nativePollOnce方法返回。

消息处理

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

               +------+         +-------+                                                                    

               |Looper|         |Handler|                                                                    

               +--+---+         +---+---+                                                                    

                |                 |                                                                        

                |                 |                                                                        

    loop()      |                 |                                                                        

    [after   next()]              |                                                                        

    +---------> |                 |                                                                        

                |                 |                                                                        

                |dispatchMessage()                                                                      

                +-------------> |                                                                        

                |                 |                                                                        

                |                 |                                                                        

                |                 | handleMessage()                                                        

                |                 +-------+                                                                

                |                 |         |                                                                

                |                 |         |                                                                

                |                 | <-----+                                                                

                |                 |     (callback   or subclass)                                              

                |                 |                                                                        

                +                 +                                                                        

 

Looper对象的loop方法里面的queue.next方法如果返回了message,那么handler的dispatchMessage会被调用。
a. 如果新建Handler的时候传入了callback实例,那么callback的handleMessage方法会被调用。
b. 如果是通过post方法向handler传入runnable对象的,那么runnable对象的run方法会被调用。
c. 其他情况下,handler方法的handleMessage会被调用。


0人推荐
随时随地看视频
慕课网APP