消息循环

2015-8-2 chenhui 消息机制

Android 的应用程序是消息驱动的,什么叫消息驱动?就是有一个由管道或 Socket 实现的消息队列,进程在入口函数的最后会一直不停地读这个消息队列,消息队列无消息时阻塞,一有消息就唤醒处理。


关键是,Android 怎么实现这个机制?这是本文要探讨的。


在 Android 中,使用 Message 类描述消息,MessageQueue 类描述消息队列,使用 Handler 来发送和处理消息队列,使用 Looper 类来创建队列和控制进程的阻塞唤醒。


他们之间的关系是:Looper 用来实现进程的阻塞和唤醒;MessageQueue 用来存储消息;Handler 用来把一个消息放倒 MessgeQueue 里,然后唤醒被 Looper 阻塞的进程,让他来处理这个消息,当然 Looper 被唤醒之后,不会自己处理,而是把这个消息提交给一个 Handler 处理,这个 Handler 往往和发送这个消息的 Handler 是同一个 Handler,这么说好像有点奇怪,其实不然,消息循环是线程之间的信息通讯,A 线程创建消息循环机制后把 Handler 传递给其他线程,并开始等待,然后其他线程把一个消息发送到 Handler 里,这样 A 线程会被唤醒,然后 A 线程再通过 Handler 提供的方法来处理这个消息


Looper 是怎么实现进程的唤醒和阻塞?

一个线程本身并不带消息循环,消息循环是需要我们主动创建的(主线程除外),我们可以调用 Looper 类的 prepare() 方法创建消息循环。prepare() 这个方法会创建一个 Looper 类和 MessageQueue 类并保存在线程的私有数据里,MessageQueue 类在这里并不重要,重要的是 Looper 类的构造函数:他创建了一个管道和一个 Epoll 对象,并把管道文件加入 Epoll 的监听范围。


这样就结束了,因为 prepare() 只是创建消息循环,并没有开始消息循环。

开始消息循环,需要调用 prepare() 创建的 Looper 对象的 loop() 方法,这个方法里面有一个死循环,这个死循环先检查 MessageQueue 里有没有消息,如果没有就调用 epoll_wait() 等待被唤醒。


这里又有一个问题:为什么要调用 epoll_wait() 等待被唤醒?看起来好像是用管道发送消息以实现线程间通讯。其实不是这样,这里的 Epoll 只是起到阻塞和唤醒的作用。消息的传递还是通过 MessageQuuee 实现的。发送者先把消息挂到 MessageQueue 里,然后往管道里写一个数据,这样 epol_wait() 就会返回,又回到死循环的开头,然后就会检查到挂在 MessageQueue 里的数据,并开始处理。


消息的发送和处理的过程是怎么样的?

在上面已经介绍了消息循环的创建方式,但仅仅是创建消息循环是没什么用的,你需要给其他线程提供一个用来和我通信的接口,也就是 Handler。


我们在创建消息循环后,可以再创建一个 Handler 对象,这个 Handler 对象在创建成功后会自动和保存在线程私有数据里的 Looper 对象和 MessageQueue 对象进行绑定。


然后我们可以把这个 Handler 对象传递给其他线程,其他线程得到 Handler 对象后,可以调用 Handler 对象的 sendMessage(Message ) 方法来传递一个消息,sendMessage() 会把消息的目标设为自身,然后挂到已经绑定了的 MessageQueue 里,然后往保存在 Looper 对象里的管道写一个字符,这样就会被唤醒,唤醒成功后回到死循环开头并检测到有消息来到,就会调用他的目标(他的目标就是 Handler 自身,发送和处理都是一个 Handler)的 dispatchMessage() 方法来处理消息,dispatchMessage() 方法会根据各自情况调用不同的函数进行处理,比如在创建 Handler 对象时传入了 Running 对象,就会调用他的 run() 方法,不然就会调用 Handler 的 handleMessage() 方法来处理。


一般来说,我们可以重写 Handler 的 handleMessage(Message),以达到处理消息的目的。


唉,其实这个没什么好说的,实在是太简单的东西。贴代码未免啰嗦,就这样吧。





发表评论:

Copyright ©2015-2016 freehui All rights reserved