摘要:如果没有,线程就会进入睡眠状态,反之会对消息进行分发处理。利用的机制,可以做到当管道没有消息时,线程睡眠在读端的上,当其他线程往管道写数据时,本线程便会被唤醒以进行消息处理。方法会堵塞线程直到有消息到来为止。
Android的消息处理机制主要分为四个部分:
创建消息队列
消息循环
消息发送
消息处理
主要涉及三个类:
MessageQueue
Looper
Handler
Android应用程序每启动一个线程,都为其创建一个消息队列,然后进入到一个无限循环之中。然后不断检查队列中是否有新消息需要处理。如果没有,线程就会进入睡眠状态,反之会对消息进行分发处理。
下面根据上面所说的进行详述。
创建消息队列整个创建过程涉及到两个类:MessageQueue 和 Looper。它们在C++层有两个对应的类:NativeMessageQueue和Looper。其关系如下图所示:
+------------+ +------+ |MessageQueue+----^+Looper| +-----+------+ +------+ | | | +-----------+------+ +------+ |NativeMessageQueue+^----+Looper| +------------------+ +------+ A----^B表示B中保存A的引用
创建过程如下所示:
Looper的prepare或者prepareMainLooper静态方法被调用,将一个Looper对象保存在ThreadLocal里面。
Looper对象的初始化方法里,首先会新建一个MessageQueue对象。
MessageQueue对象的初始化方法通过JNI初始化C++层的NativeMessageQueue对象。
NativeMessageQueue对象在创建过程中,会初始化一个C++层的Looper对象。
C++层的Looper对象在创建的过程中,会在内部创建一个管道(pipe),并将这个管道的读写fd都保存在mWakeReadPipeFd和mWakeWritePipeFd中。
然后新建一个epoll实例,并将两个fd注册进去。
利用epoll的机制,可以做到当管道没有消息时,线程睡眠在读端的fd上,当其他线程往管道写数据时,本线程便会被唤醒以进行消息处理。
消息循环+------+ +------------+ +------------------+ +--------------+ |Looper| |MessageQueue| |NativeMessageQueue| |Looper(Native)| +--+---+ +------+-----+ +---------+--------+ +-------+------+ | | | | | | | | +-------------------------------------------------------------------------------+ |[msg loop] | next() | | | | | +------------> | | | | | | | | | | | | | | | | | | | nativePollOnce() | | | | | | pollOnce() | | | | | +----------------> | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | pollOnce() | | | | | +-----------------> | | | | | | | | | | | | | epoll_wait() | | | | +--------+ | | | | | | | | | | | | | | | | | | | | <------+ | | | | | | awoken() | | + + + + | | | | | +-------------------------------------------------------------------------------+
首先通过调用Looper的loop方法开始消息监听。loop方法里会调用MessageQueue的next方法。next方法会堵塞线程直到有消息到来为止。
next方法通过调用nativePollOnce方法来监听事件。next方法内部逻辑如下所示(简化):
a. 进入死循环,以参数timout=0调用nativePollOnce方法。
b. 如果消息队列中有消息,nativePollOnce方法会将消息保存在mMessage成员中。nativePollOnce方法返回后立刻检查mMessage成员是否为空。
c. 如果mMessage不为空,那么检查它指定的运行时间。如果比当前时间要前,那么马上返回这个mMessage,否则设置timeout为两者之差,进入下一次循环。
d. 如果mMessage为空,那么设置timeout为-1,即下次循环nativePollOnce永久堵塞。
nativePollOnce方法内部利用epoll机制在之前建立的管道上等待数据写入。接收到数据后马上读取并返回结果。
消息发送+-------+ +------------+ +------------------+ +--------------+ |Handler| |MessageQueue| |NativeMessageQueue| |Looper(Native)| +--+----+ +-----+------+ +---------+--------+ +-------+------+ | | | | | | | | sendMessage()| | | | +----------> | | | | | | | | |enqueueMessage()| | | +--------------> | | | | | | | | | | | | | | | | | nativeWake() | | | | wake() | | | +------------------> | | | | | | | | | wake() | | | +------------------> | | | | | | | | | | | | |write(mWakeWritePipeFd, "W", 1) | | | | | | | | | | | | | | | | | | | | + + + +
消息发送过程主要由Handler对象来驱动。
Handler对象在创建时会保存当前线程的looper和MessageQueue,如果传入Callback的话也会保存起来。
用户调用handler对象的sendMessage方法,传入msg对象。handler通过调用MessageQueue的enqueueMessage方法将消息压入MessageQueue。
enqueueMessage方法会将传入的消息对象根据触发时间(when)插入到message queue中。然后判断是否要唤醒等待中的队列。
a. 如果插在队列中间。说明该消息不需要马上处理,不需要由这个消息来唤醒队列。
b. 如果插在队列头部(或者when=0),则表明要马上处理这个消息。如果当前队列正在堵塞,则需要唤醒它进行处理。
如果需要唤醒队列,则通过nativeWake方法,往前面提到的管道中写入一个"W"字符,令nativePollOnce方法返回。
消息处理+------+ +-------+ |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会被调用。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/12315.html
摘要:异步消息传递所涉及的相关概念主线程线程,程序启动时自动创建。消息接受处理的对象,存储需要操作的消息。至此,关于的异步消息传递机制的解析就完成了。 前言 在Android开发中,多线程应用是非常频繁的,其中Handler机制随处可见. 下面就本人对Handle的一些理解与大家一起分享,共同回顾下Handle异步消息传递机制。 1.Handler是什么? Handler是一套在 An...
摘要:创建和,本来该线程也是一个普通的线程,但是创建了以及结合后文的方法,使这个线程成为了线程读者可以简单的理解为拥有的线程,而这个就是消息处理机制的一部分。不过这不影响我们分析的消息机制的整个流程。 该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索》以及《深入理解Android ...
摘要:静态集合类引起内存泄露主要是,等,如果是静态集合这些集合没有及时的话,就会一直持有这些对象。关于合理使用内存,其实就是避免内存泄露中已经说明。参数原生参数元素需要支持机制参考进程线程管理一消息机制的框架这个系类。 阅读目录 1.如何对 Android 应用进行性能分析 2.什么情况下会导致内存泄露 3.如何避免 OOM 异常 4.Android 中如何捕获未捕获的异常 5.ANR 是...
摘要:一基本概念什么是消息机制不同线程之间的通信。什么安卓的消息机制,就是运行机制。安卓的消息机制有什么用避免,一旦发生,程序就挂了,奔溃了。安卓采取的方法是,主线程应该为子线程提供一个,以便完成时能够提交给主线程。 能简单说得我们尽量不复杂: 为了避免ANR,我们会通常把 耗时操作放在子线程里面去执行,因为子线程不能更新UI,所以当子线程需要更新的UI的时候就需要借助到安卓的消息机制,也就...
摘要:一基本概念什么是消息机制不同线程之间的通信。什么安卓的消息机制,就是运行机制。安卓的消息机制有什么用避免,一旦发生,程序就挂了,奔溃了。安卓采取的方法是,主线程应该为子线程提供一个,以便完成时能够提交给主线程。 能简单说得我们尽量不复杂: 为了避免ANR,我们会通常把 耗时操作放在子线程里面去执行,因为子线程不能更新UI,所以当子线程需要更新的UI的时候就需要借助到安卓的消息机制,也就...
阅读 4403·2021-09-22 16:06
阅读 1848·2021-09-22 15:22
阅读 1219·2019-08-30 15:54
阅读 2347·2019-08-30 15:44
阅读 2224·2019-08-29 16:31
阅读 1909·2019-08-29 16:26
阅读 2223·2019-08-29 12:41
阅读 624·2019-08-29 12:22