安卓基础组件Looper - 01 通讯机制简介
文章目录
- 为什么需要 Looper
- 成员
- MessageQueue
- Looper
- Handler lambda
- 机制图
为什么需要 Looper
main函数/普通函数执行完后,整个进程/线程也就结束了。为了让处理可执行对象的进程/线程长时间运行,需要无限循环加事件通知的机制。
int main()
{
while(true)
{
1. 线程进入休眠状态,等待通知;
2. 其它地方给当前线程发送通知,线程从休眠中唤醒,读取通知,处理通知
3. 进入下一个循环
}
return 0;
}
成员
MessageQueue
MessageQueue:装message的容器。
-
使用 pool 享元设计模式。
-
有消息处理,数量不能过多。pool会超出容量。
-
根据时间排序,
-
当
message queue队列
满的时候,阻塞,直到用户通过next取出消息。 -
当出队
next方法
被调用,通知MessagQueue可以进行消息的入队。
// frameworks/base/core/java/android/os/MessageQueue.java boolean enqueueMessage(Message msg, long when) {
-
生产者消费者
-
入队 生产者:子线程 向消息队列添加消息和Handler
-
出队 消费者工作线程:工作线程依此轮循,轮询到了MSG就会执行
- java 执行了
Looper.loop()
的线程(往往是主线程。因此MSG的消费,执行,都在主线程中) - cpp
Looper::prepare
/new Looper
的线程
- java 执行了
数量关系:(有说法是每个进程只有一个MessageQueue。但我看起来是觉得每个工作线程都有且只有一个MessageQueue)
-
java
// frameworks/base/core/java/android/os/Looper.java 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)); } // sThreadLocal.get() will return null unless you've called prepare(). @UnsupportedAppUsage static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
-
native
class Looper : public RefBase { Vector<MessageEnvelope> mMessageEnvelopes; // guarded by mLock
Looper
在线程(一般是主线程)中执行Looper.loop()
,则这个线程就是“工作线程”。可以认为是MSG的消费者:所有的MSG的消费,执行都是在该线程中。
-
调用了
Looper::loop()
的线程,会从进程的MessageQueue中取出、处理MSG,并执行Hanlder的重载。 -
因为 MessageQueue 是线程安全的,所以可以有多个线程调用
Looper::loop()
,这些线程并行的处理Hanlder。
对于app来说,这个“工作线程”就是主线程。app启动/挂断,一定是从主线程的 main函数 开始的
// frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
// 准备loop
Looper.prepareMainLooper();
Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
// 让loop运行起来. 一直循环,保障进程一直执行,如果退出,说明程序关闭
Looper.loop();
数量关系:进程中可以在进程中指定一个/多个工作线程,每个工作线程拥有一个Looper
-
一个线程只允许有一套Handler通讯机制,只有一个Looper
在native层 一个线程new多个Looper是不建议的,但神奇的是这往往并不会出错,符合能跑就行的思想。
-
一个进程可以有多个工作线程,从而一个进程中可有多个Looper
Handler lambda
狭义的来说
- Handler是一个类,一个线程有多个 Handler对象 ——设计模式命令模式
- 定义 Handler时,需要指定 Looper 意味着于此同时确定了对应的MessageQueue和工作线程。
- 各个线程怎么区分其中的msg该让哪个Handler执行呢?
- Handler.sendMessage时会把this(也就是哪个Handler)传递给MessageQueue。
- 所以,才能让对应 Handler 执行其 handleMessage方法
广义来说:Handler是一种线程通信的方案。
-
作为方案,MessageQueue和Looper也包含其中
-
实际上是内存共享的方案
-
MessageQueue这个容器 在同一进程中的线程间是 共享 的,
-
主线程可以通过loop死循环去不断的访问 MessageQueue。
-
为什么 wait/notify用处不大:因为handler已经将需要这部分功能进行了Linux层的封装 使用epoll多路IO复用进行管理。
机制图
解决线程之间的通讯:(并不跨进程)
其他跨线程通信:retrofit,eventbus,rxjava都是使用了主线程MainThread的,底层都使用了Handler机制(Looper机制)