Handler-MessageQueue-Looper是Android特有的线程间通信机制。
Handler
Handler作为面向开发者的类,每种功能都复写了很多不同的方法,以达到方便开发者调用的目的:
Handler构建
Handler的构造最主要方法如下:
1 | public Handler(Looper looper, Callback callback, boolean async) { |
需要获取一下四个成员变量:
- looper 指定的looper,与线程有关
- messageQueue looper的messageQueue
- callback 可空
- mAsynchronous 是否异步
Handler发送消息
上面的这些方法最终会调用一下方法:
1 | public boolean sendMessageAtTime(Message msg, long uptimeMillis) { |
这里调用messageQueue的enqueue方法将消息加入消息队列:
1 | boolean enqueueMessage(Message msg, long when) { |
可以看出,将消息插入消息队列分为两种情况:
- 如果当前消息最先需要处理,那么就插入队首
- 如果不是需要最先处理,那么遍历整个队列,按消息需要处理的时间先后顺序插入消息
Handler拿一个未发送的message
obtainMessage最终调用如下方法:
1 | Hanlder.class |
最终调用Message类的obtain()方法,Message的obtain()方法通过从Message类中维护的消息池(sPool)中获取之前已经使用过的消息,如果消息池中没有消息,那就返回一个新的消息,这样中可以减少消息对象的创建。
Handler处理消息
1 | public void dispatchMessage(Message msg) { |
这里如果在构造Handler的时候加入了mCallback对象,那会就会执行mCallback对象的handleMessage()方法,否则执行Handler对象的handleMessage()方法。所以在我们写handler代码的时候都回去重写handleMessage(Message msg)方法,来处理handler发送消息。
开发中使用API主要就是以上的部分,下面开始分析,消息的处理机制。
Looper
Looper类在普通的开发中很难使用到,但是它缺少消息机制中重要的一个部分:负责轮询,并分发消息给相应的handler进行处理。
Looper是与线程紧密联系的一个类,Looper类中维护了一个ThreadLocal对象,用于存放不同线程的Looper对象:static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
Looper对象的构造是通过Looper.prepare()方法实现的:
1 | public static void prepare() { |
looper的执行只有一个方法,这个方法会进入一个死循环,在循环中不断获取消息队列中的消息然后分发给相应的handler进行处理:
1 | public static void loop() { |
Looper.loop在循环中主要做了三件事:
- 从消息队列MessageQueue中获取消息
- 将获取的消息给相应的handler进行处理
- 将处理完的消息进行回收
想看第一点,Message msg = queue.next(); // might block
源码的注释上写到:might block(有可能阻塞)。进入MessageQueue的next()方法:
1 | Message next() { |
next()使用nativePollOnce(ptr, nextPollTimeoutMillis);
方法,在没有消息的时候进行阻塞,当有消息的时候再从mMessages中获取消息,然后判断是否到到执行消息的时间,如果到了就返回消息,否则就计算要等待的时间,然后下一次循环再调用nativePollOnce()
方法进行阻塞,直到消息需要执行了,然后返回消息。
nativePollOnce()
方法是一个native的方法:
1 | /frameworks/base/core/jni/android_os_MessageQueue.cpp |
long ptr
是java层线程创建Looper的时候创建MessageQueue时从native层获取的,对应的就是native 层的MessageQueue。android_os_MessageQueue_nativePollOnce方法会通过ptr先获取nativeMessageQueue对象,然后调用nativeMessageQueue的pollOnce方法:
1 | void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) { |
最终调用mLooper->pollOnce(timeoutMillis);方法,当消息队列中没有消息,timeoutMillis(Java层的nextPollTimeoutMillis)= -1,就会阻塞。只有当新加入消息的时候会调用nativeWake(mPtr);
native方法:
1 | static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) { |
最终调用mLooper->wake();
唤醒mLoop,此时nativePollOnce
方法往后执行,messageQueue.next()
才能获取message并返回。
至此,
- 从handler发送消息
- messageQueue将消息入队列
- looper轮询调用messageQueue的 next方法获取下一个需要处理的消息
- looper将消息分发给handler进行处理
整个流程完毕
总结
handler消息处理有一下几个大块:
- looper使用死循环轮询消息,使线程一直运行并监控发来的消息然后处理
- 在轮询的时候核心是通过messageQueue的next方法获取下一个要处理的消息,这里使用native层调用
epoll_wait
和epoll_clt
进行线程的阻塞和唤醒 - handler的obtain方法最终使用的是message的obtain方法,message类中维护类一个message池,为handler提供空白消息,池化的做法可以避免频繁创建对象,导致频繁GC