消息处理机制
简单一句话:
Handler获取当前线程中的looper对象,looper用来从存放Message的MessageQueue中取出Message, 再有Handler进行Message的分发和处理.
来张动图:

应用开始
从整个应用开始来看,Looper先开始准备,然后调用loop()方法
loop()方法里面会一直循环,使得整个主线程一直在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
....
Process.setArgV0("<pre-initialized>");
// Lppper开始准备
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
// attach方法其实在thread里面便会创建一个Binder线程
// 这也就是为什么死循环后程序还能运作的原因
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) { // 条件是false进不来
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// Loop 开始循环,主线程进入了死循环
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
... |
由此而来,我们一般会有2个问题:
(1) Android中为什么主线程不会因为Looper.loop()里的死循环卡死?
(2) 没看见哪里有相关代码为这个死循环准备了一个新线程去运转?
知乎上的回答(十分赞):点这里
有了这个引入后,接下来将会从Looper,Handler,Message,MessageQuene逐个分析
Looper
一般一个线程就对应一个Looper
重要成员有:
1 2 3 4 5 6 7 8 9 |
// ThreadLocal使得每个Thread都有一个自己的副本 // 这样就可以保证每个线程中都有一个自己的Looper,不会被别的线程共享 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); // 主线程中的Looper private static Looper sMainLooper; // guarded by Looper.class // MessageQueue 消息队列用作保存和取出Message final MessageQueue mQueue; // 当前线程 final Thread mThread; |
从开始我们可以先从Looper.prepareMainLooper()方法下手
其实就是调用了Looper中的prepare方法,
1 2 3 4 5 6 7 8 9 10 11 |
// quitAllowed
// 是否允许退出,这里主线程的时候是传入false,
//最后会在MessageQuene中的quit方法中抛出异常,从而不让退出
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//sThreadLocal 就像一个Map,一个新建的Looper给放进去
//类似一个线程对应一个Looper
sThreadLocal.set(new Looper(quitAllowed));
} |
这里就到了Looper的构造方法:
1 2 3 4 5 6 |
// 这里把之前的quitAllowed给传进了MessageQueue;
// 并且mThread是当前的线程
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
} |
接下来就是核心方法loop():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
public static void loop() {
// 获取loop和queue
final Looper me = myLooper();
if (me == null) { //没有消息,退出循环,程序退出
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
//主要是为了确保是否还是当前进程
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) { // 这里就是死循环了
// 取出msg,如果为空,return掉
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
// target 就是 Handler,这里就会调用Handler的dispatchMessage方法发送消息
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...
// 将Message回收到消息池,下次要用的时候不需要重新创建,obtain()就可以了。
msg.recycleUnchecked();
}
} |
这里有个问题,主线程是UI线程和用户交互的线程,优先级应该很高,主线程的死循环一直运行是不是会特别消耗CPU资源吗?App进程的其他线程怎么办?
关键就是queue.next()方法里,如果此时没有消息,就会阻塞在这个方法里面。这时候主线程会释放CPU资源进入休眠状态,直到有下个消息进来时候就会唤醒主线程
.2 版本以前,这套机制是用我们熟悉的线程的wait和notify 来实现的,之后的版本涉及到Linux pipe/epoll机制,通过往pipe管道写端写入数据来唤醒主线程工作。原理类似于I/O,读写是堵塞的,不占用CPU资源。
MessageQuene
先看下构造方法:
1 2 3 4 5 6 7 |
MessageQueue(boolean quitAllowed) {
// 之前的是否允许退出
mQuitAllowed = quitAllowed;
// 可以理解为当前队列是否还有没效,0就是没,大于0就是有
// 后面的dispose方法就是让其无效,从而退出程序
mPtr = nativeInit();
} |
继续刚才,进入到queue.next()方法中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
Message next() {
final long ptr = mPtr;
if (ptr == 0) { // 队列无效,返回空退出程序
return null;
}
int pendingIdleHandlerCount = -1;
int nextPollTimeoutMillis = 0;
// 又来一个死循环了
for (;;) {
...
// 该方法会阻塞队列
// 1.没消息的时候
// 2.nextPollTimeoutMillis>0,而且等待时间还没到
nativePollOnce(ptr, nextPollTimeoutMillis);
// 返回继续执行
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
// 如果mMessages当前消息不为空,handler不为空,也不是异步消息,
// 把当前消息返回
if (msg != null && msg.target == null) {
// 否则一直查找下去,直到是一条target不为空也不是异步的消息
// 如果是异步消息,则跳出循环
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
// 如果mMessages不为空
if (msg != null) {
if (now < msg.when) {
// 时间还没到,要等下次,经常用的postDelay,
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;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
// 最后返回消息
return msg;
}
} else {
// 没有消息 ,重新把时间变成-1
nextPollTimeoutMillis = -1;
}
}
} |
这里就把queue.next()给分析完了,那问题是mMessages又是如何得到呢?
这里就是Handler发送消息的时候使用了enqueueMessage方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
boolean enqueueMessage(Message msg, long when) {
// 如果target为空,或者消息正在使用 都抛出异常
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
// 如果消息队列正在退出,回收消息
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
// 消息标记为使用中 flags |= FLAG_IN_USE
msg.markInUse();
msg.when = when; // 消息发送时间
Message p = mMessages; //当前消息
boolean needWake; //是否需要唤醒
// 当前没有消息需要执行或者当前的消息执行时间比msg要大,说明,msg应该第一个执行
if (p == null || when == 0 || when < p.when) {
// 当前mMessages变为要msg
msg.next = p;
mMessages = msg;
// mBlocked 是否正在阻塞中,如果是,需要唤醒
needWake = mBlocked;
} else {
// 如果消息是异步的,p又没有target,而且还在阻塞中,变为要唤醒
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
// 在当前消息队列中查找是否有消息比这个msg应该提前执行的,
// 如果有就不执行
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;
}
// 如果需要唤醒,则唤醒,next方法()
if (needWake) {
nativeWake(mPtr);
}
}
return true;
} |
Message
消息,类似一个Model一样,主要是一些信息
里面有几个重要参数
1 2 3 4 5 6 |
// 锁对象 private static final Object sPoolSync = new Object(); // 消息池,就像一个链表一样,指向当前的消息 private static Message sPool; // 消息池的大小 private static int sPoolSize = 0; |
主要方法:obtain(),这里也就对应了之前为什么在Loopr最后调用msg.recycleUnchecked();
因为Message类可以看成是个单例模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 没什么好说的,就是从消息池中获取一个消息,如果没有,就new一个
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
} |
当前消息变为新的消息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public static Message obtain(Message orig) {
Message m = obtain();
m.what = orig.what;
m.arg1 = orig.arg1;
m.arg2 = orig.arg2;
m.obj = orig.obj;
m.replyTo = orig.replyTo;
m.sendingUid = orig.sendingUid;
if (orig.data != null) {
m.data = new Bundle(orig.data);
}
m.target = orig.target;
m.callback = orig.callback;
return m;
} |
Handler
Handler算是我们平时用的最多一个类
几个重要参数:
1 2 3 4 |
final Looper mLooper; // 所在的Looper,默认主线程 final MessageQueue mQueue; // 所在消息队列 final Callback mCallback; // callBack 最后回调 handleMessage 方法 final boolean mAsynchronous; // 是否异步 传给了消息的 mAsynchronous |
我们一般使用都会重写该handleMessage方法
1 2 3 4 5 |
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
} |
这里对于dispatchMessage方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public void dispatchMessage(Message msg) {
// 消息的callback不为空 , 执行消息的
if (msg.callback != null) {
handleCallback(msg);
} else {
// callback 不为空 执行 callback
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// 最后才执行
handleMessage(msg);
}
} |
在看下平时经常用的几个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
1.
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
2.
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
3.
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
4.
public final boolean post(Runnable r)
{
// getPostMessage 也就是消息的构建一个callback = r 的消息
return sendMessageDelayed(getPostMessage(r), 0);
} |
都会调用了sendMessageDelayed方法:
1 2 3 4 5 6 7 8 9 10 |
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
} |
最终调用了enqueueMessage方法,触发queue.enqueueMessage:
1 2 3 4 5 6 7 |
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; // 这里赋予target
if (mAsynchronous) { //如果是异步的话
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
} |
结尾
至此,已经大致把整个消息机制基本流程分析了一遍,当然里面还有很多细节没有分析, 当然你也可以看看HandlerThread类,在研究下