MessageQueue
我们知道Android提供了Handler 和 Looper 来满足线程间的通信,之前通过Handler和Looper的学习,知道
1、子线程通过Handler对象来与Looper(一个线程可以产生一个Looper对象)沟通,
2、push新消息到MessageQueue里;或者接收Looper从Message Queue取出)所送来的消息。
3、将消息放到Looper的MessageQueue中。
4、Looper收到消息后就开始处理了,
5、由Looper交由Handler处理,Handler最终将消息发送给主线程。
那么我们今天就来讲讲MessageQueue!
一:变量
//mQuitAllowed表示MessageQueue是否允许退出,系统创建的UI线程的MessageQueue是不允许的,其他客户端代码创建的都是允许的;
private final boolean mQuitAllowed;
//mPtr是native代码相关的,指向C/C++代码中的某些对象(指针)
private long mPtr; // used by native code
//mMessages表示消息队列的头Head;
Message mMessages;
//mIdleHandlers是IdldHandler接口的ArrayList, mPendingIdleHandlers是数组版本,在后面的代码中会将ArrayList的内容拷贝到它里面;
private final ArrayList mIdleHandlers = new ArrayList();
//IdleHandler接口表示当MessageQueue发现当前没有更多消息可以处理的时候则顺便干点别的事情的callback函数
private IdleHandler[] mPendingIdleHandlers;
//表示当前队列是否处于正在退出状态;
private boolean mQuitting;
// Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
//mBlocked表示next()调用是否被block在timeout不为0的pollOnce上;
private boolean mBlocked;
//mNextBarrierToken表示下一个barrier token,barrier用target==null, arg1==token的Message对象表示;
private int mNextBarrierToken;
//注:ctor中初始化mQuitAllowd和native的mPtr指针;
二、方法
MessageQueue作为Message存储的一个单链表,重要的是两个方法,enqueueMessage和next。enqueueMessage其主要操作是向MessageQueue单链表中插入数据。主要看一下next方法。
通过代码片段:
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
、、、
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
return msg;
}
可以发现next是是一个无限循环的方法,唯一跳出循环的条件是取出MessageQueue中的msg,然后return msg (同时将Message从MessageQueue中移除)。如果MessageQueue 中没有消息,那么next方法将一直阻塞在这里,只有执行Loop.quit/quitSafely才会跳出循环。如果MessageQueue中有Message则执行msg.target.dispatchMessage(msg)。
那么问题来了。。
这里死循环了,那Activity怎么响应onCreate或者按钮的点击事件呢?
Activity内部真正运行的是ActivityThread,ActivityThread的内部类H继承于Handler,通过handler消息机制,简单说Handler机制用于同一个进程的线程间通信。Activity的生命周期都是依靠主线程的Looper.loop,当收到不同Message时则采用相应措施:在H.handleMessage(msg)方法中,根据接收到不同的msg,执行相应的生命周期。也就是说这个死循环是为了给Activity处于一种时刻运行状态的机制。
最后引申一下:
从进程与线程间通信的角度,通过一张图加深大家对App运行过程的理解:
结合图说说Activity生命周期,比如暂停Activity,流程如下:线程1的AMS中调用线程2的ATP;(由于同一个进程的线程间资源共享,可以相互直接调用,但需要注意多线程并发问题)线程2通过binder传输到App进程的线程4;线程4通过handler消息机制,将暂停Activity的消息发送给主线程;主线程在looper.loop()中循环遍历消息,当收到暂停Activity的消息时,便将消息分发给ActivityThread.H.handleMessage()方法,再经过方法的调用,最后便会调用到Activity.onPause(),当onPause()处理完后,继续循环loop下去。
引申内容的作者:Gityuan