Android线程间消息传递机制
一、线程的消息队列的创建原理
1、可以在子线程创建Handler么?
在子线程里创建handler:
Thread {
Handler()
}.start()
会抛出以下异常:
意为不能在没有调用prepare函数的线程内创建handler。
为什么会抛出这个异常呢,我们去翻下源码。
下面是Handler的构造函数:
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
....
// 获取当前线程的Looper对象,此对象保存在ThreadLocal中
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
而looper的创建是在Looper类的prepare方法中创建的:
// 注,有一个参数,含义为是否允许退出
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));
}
// 创建主线程的looper
public static void prepareMainLooper() {
// 主线程的looper不允许退出,故传参false
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
// 主线程looper创建成功后,保存到一个静态变量里,可随时获取
sMainLooper = myLooper();
}
}
Looper的构造函数:
private Looper(boolean quitAllowed) {
// 创建MessageQueue
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
MessageQueue的构造函数:
MessageQueue(boolean quitAllowed) {
// 保存是否允许退出的变量
mQuitAllowed = quitAllowed;
// 真正的初始化在native层去做
mPtr = nativeInit();
}
线程Thread、Looper、MessageQueue、Handler之间的关系如下图所示:
一个线程里存在一个Looper,Looper是保存在ThreadLocal中的,一个Looper里面保存一个MessageQueue,MessageQueue接收不同的Handler发过来的Message,然后不断轮询其中的Message,如果存在Message,就把Message交给对应的Handler处理,Handler与Message的对应关系由Message当中的一个target属性来确定。
然后继续看MessageQueue的native层的初始化过程:
// native层的初始化方法
jlong android_os_MessageQueue_nativeInt(JNIEnv* env, jclss clazz){
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
return reinterpret_cast<jlong>(naticeMessageQueue);
}
// natvie层的MessageQueue的构造方法
NativeMessageQueue::NativeMessageQueue(){
mLooper = Looper::getForThread(); // 获取局部缓存
// 如果局部缓存为空
// 则创建一个natice层的Looper,并放到局部缓存中
if(mLooper == NULL){
mLooper = new Looper(false);
Looper::setForThread(mLooper);
}
}
然后是native层的Looper的构造函数:
Looper::Looper(bool allowNonCallbacks){
mWakeEventFd = eventfd(0,EFD_NONBLOCK); // 创建fd
rebuildEpollLocked();
}
native层的looper是整个消息循环的核心部分,在其构造方法中,创建了一个fd,在早起的版本中,此处不是创建fd,而是采用普通的管道,因为管道涉及到内存的两次拷贝,所以后来的版本中采用性能更好的fd,其内部就是一个计数器,避免了两次拷贝。
然后是rebuildEpollLocked()函数,此函数是将上面的fd加入epoll的监听队列中:
void Looper::rebuildEpollLocked(){
// 创建一个epoll
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
......
// 将fd添加到epoll的监听队列中,监听它的读事件
struct epoll_event eventItem;
memset(&eventItem,0,sizeof(epoll_event));
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeEventFd;
epoll_ctl(mEpollFd,EPOLL_CTL_ADD,mWakeEventFd,&eventItem);
......
}
真正的监听是在下方的一个死循环中:
int Looper::pollOnce(int timeoutMills, int* outFd,...){
for(;;){
pollInner(timeoutMills);
}
}
int Looper::pollInner(int timeoutMills){
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
// 阻塞方法,等待事件发生
int eventCount = epoll_wait(mEpollFd, eventItems,...);
// 如果有时间,就在循环中处理
for(int i = 0; i < eventCount; i++){
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if(fd == mWakeEventFd && (epollEvents & EPOLLIN)){
// 如果事件是之前监听的那个计数器,且是读事件,则取出来消耗掉
awoken(); // 消耗的方法
}
}
}
2、主线程的Looper和子线程的Looper有什么区别?
子线程的Looper是可以退出的,主线程的Looper是不能退出的。
3、Looper和MessageQueue、Handler有什么关系?
java层中,Looper和MessageQueue是一对一的关系,native层中,NativeMessageQueue是包含一个native层Looper的,也是一对一的关系。
4、MessageQueue是怎么创建的?
java层的MessageQueue的构造函数会调用一个native函数去创建native层的NativeMessageQueue,NativeMessageQueue中会创建一个Looper,Looper中会创建一个eventfd, 并创建epoll, 然后添加fd的可读事件到epoll中。
二、消息的循环过程
消息循环就是Looper的loop函数:
public static void loop() {
// 拿到当前线程的looper
final Looper me = myLooper();
...
// 然后拿到looper对应的MessageQueue
final MessageQueue queue = me.mQueue;
...
for (;;) {
// 在循环中,不断地取下一条消息
Message msg = queue.next(); // might block,如果说队列为空,则阻塞在这里
if (msg == null) {
// No message indicates that the message queue is quitting.
// 没有消息说明Looper结束了,直接return
return;
}
try {
// 使用msg对应的handler,分发message,
msg.target.dispatchMessage(msg);
} finally {
...
}
...
// 回收message,即重置message状态,并放入对象池(单链表)
msg.recycleUnchecked();
}
}
其中,最重要的两步,即取消息和分发消息。
先看取消息:MessageQueue中的next()方法
Message next() {
...
int nextPollTimeoutMillis = 0;
for (;;) {
...
//阻塞在这,等待其他线程发消息过来,或者超过超时时间,被唤醒返回
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
// 此处跟消息屏障有关,还没看明白
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
// 下面是正常消息处理流程
if (msg != null) {
if (now < msg.when) {
// 如果消息没准备好,设置超时时间,等消息准备好了再唤醒
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 如果消息准备好了,获取消息
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
// 消息标志为使用
msg.markInUse();
return msg;
}
} else {
// 如果没有消息,说明队列为空,则超时时间设置为-1,阻塞等待消息来
nextPollTimeoutMillis = -1;
}
.......
}
}
nativePollOnce:
void android_os_MessageQueue_naticePollOnce(JNIEnv* env, jobject obj,jlong ptr, jint timeoutMillis){
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->pollOnce(env,obj,timeoutMills);
}
void NativeMessageQueue::pollOnce(JNIEnv* env,jobject pollObj,int timeoutMillis){
......
// 核心,循环
mLooper->pollOnce(timeoutMillis);
......
}
可以看到,最终调用了native层的Looper的pollOnce函数,pollOnce函数最终又调用了其pollInner函数,此函数就是最终的监听消息的方法。
三、消息的发送过程
Handler的sendMessage,senMessageEmpty,sendMessageDelayed,post,postDelay,postAt等等方法,最终都调用到:
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
// 保存了messageQueue的引用
MessageQueue queue = mQueue;
...
// 将message和时间戳信息传入到MQ中
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
// 首先设置了message的target 为this,也就是发送消息的handler
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
然后走到MQ的enqueueMessage:
boolean enqueueMessage(Message msg, long when) {
......
synchronized (this) {
......
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
其中nativeWake,即将消息写入到队列中的底层实现,也就是往native层的looper中的eventfd中写入一个数,然后fd就可以收到此事件。
void android_os_MessageQueue_nativeWake(JNIEnv* env,jclass clazz, jlong ptr){
NativeMessageQueue* naticeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->wake();
}
nativeMessageQueue最终调用到其内部Looper的wake方法:
void Looper::wake(){
uint64_t inc = 1;
// 往mWakeEventFd当中写入一个数
write(mWakeEventFd,&inc,sizeof(uint64_t));
}
总结下,添加消息的过程,就是从java层的MessageQueue的enqueueMessage方法开始,此方法在把消息加入到消息队列中的同时,会把调用消息对应的本地MQ的wake()方法,最终通过本地Looper往一个计数器fd中写入一个数,来通知队列消息的添加,并在本地Looper的循环中监听这个计数器fd,来唤醒上层所调用的获取消息的native方法,并处理。
四、消息的分发过程
消息的分发是在Handler的dispatchMessage中
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
// 先看msg有没有callback,如果有,则直接调用handleCallback
handleCallback(msg);
} else {
// 如果msg没有callback,则看有没有全局mCallback
if (mCallback != null) {
// 如果有,则调用全局的handleMessage,之后的逻辑要看此callback的返回值,返回true,直接return;
// 只有返回false,才会执行到我们自己复写的那个handleMessage方法
if (mCallback.handleMessage(msg)) {
return;
}
}
// 我们自己复写的handleMessage方法
handleMessage(msg);
}
}