Handler消息取出和处理
消息的取出
消息的取出主要是通过Looper的loop方法。
Looper.loop()主要是消息循环,从消息队列中获取消息,分发消息到Handler中。
查看一下loop的源码。
public static void loop() {
// --- 1.获取当前Looper的消息队列MessageQueue -----
// 第一步
// 获取当前Looper对象
final Looper me = myLooper();
// myLooper()的作用是返回sThreadLocal存储的Looper实例
// 若me为null,则抛出异常
// 所以在执行loop()方法之前,必须执行prepare()方法,prepare() //的作用是创建Looper实例
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
// 第二步
// 获取Looper实例中的消息队列对象MessageQueue
final MessageQueue queue = me.mQueue;
// ......代码省略
//------ 2. 消息循环,无限循环 --------------
// 第三步
for (;;) {
// 从MessageQueue中取出消息
// 第四步
Message msg = queue.next(); // might block
// 如果消息为空,则退出循环
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// ......代码省略
final long dispatchEnd;
try {
// 第五步
// 分发消息到对应的Handler
// 把消息派发到msg的target属性
//target属性实际上是一个handler对象
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
// ......代码省略
// 第六步
// 回收消息
msg.recycleUnchecked();
}
}
消息循环Looper.loop(),主要作用的取出消息,通过以上代码分析,大致分为六步:
- 第一步,获取Looper对象
- 第二步,获取Looper实例中的消息队列对象MessageQueue
- 第三步,while()无限循环遍历
- 第四步,通过queue.next()从MessageQueue中取出一个Message对象
- 第五步,通过msg.target.dispatchMessage(msg)来处理消息
- 第六步,通过 msg.recycleUnchecked()来回收消息
其中第一二三步就别少了,第六步在
Message源码
下面介绍第四步和第五步。
MessageQueue.next()方法
MessageQueue.next()主要是从MessageQueue中取出一个Message对象,源码如下:
Message next() {
//mPtr是关联到native层的一个long型变量,只有当MessageQueue被
// 抛弃的时候(调用disposed()方法),mPtr才为0,这时直接return
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
// 记录空闲时处理的IdlerHandler的数量
int pendingIdleHandlerCount = -1; // -1 only during first iteration
// native层用到的变量,在nativePollOnce(ptr,
//nextPollTimeoutMillis)使用,
//如果nextPollTimeoutMillis=-1,一直阻塞不会超时,
//如果nextPollTimeoutMillis=0,不会阻塞,立即返回,
//如果nextPollTimeoutMillis>0,最长阻塞nextPollTimeoutMillis
//毫秒(超时),如果期间有程序唤醒会立即返回。
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// 阻塞方法
nativePollOnce(ptr, nextPollTimeoutMillis);
// 同步锁
synchronized (this) {
// 获取开机到现在的时间
final long now = SystemClock.uptimeMillis();
//标记前一个message
Message prevMsg = null;
//获取消息队列中链表表头的第一个元素
Message msg = mMessages;
//判断Message是否是同步屏障,如果是则执行循环,拦截所有同步消 //息,直到取到第一个异步消息为止。
if (msg != null && msg.target == null) {
// 如果进入这个循环,则表示MessageQueue的第一个message就是
//同步屏障消息
// 循环遍历,拦截所有同步消息,直到取出第一个异步消息
do {
prevMsg = msg;
msg = msg.next;
//退出循环的条件,msg==null,表示循环结束,
//msg.isAsynchronous()为ture表示是异步消息,则退出循环
} while (msg != null &&!msg.isAsynchronous());
}
if (msg != null) {
//判断msg是否达到了执行时间
if (now < msg.when) {
//msg没有达到执行时间,设置一下阻塞时间
//nextPollTimeoutMillis,进入下次循环的时候会调用
//nativePollOnce(ptr,nextPollTimeoutMillis)进行阻塞
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
//msg已到执行时间
//此时有消息,不能阻塞
mBlocked = false;
//如果还有上一个元素
if (prevMsg != null) {
//上一个元素的next越过自己指向下一个元素
prevMsg.next = msg.next;
} else {
//如果没有上一个元素,说明是消息队列的头元素,直接
//让第二个元素变成头元素
mMessages = msg.next;
}
//msg要取出,msg的next指向null
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
//设置msg为正在使用的状态
msg.markInUse();
// 返回msg
return msg;
}
} else {
//没有消息,会一直阻塞,直到被唤醒
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
//如果是退出状态,关闭消息队列,返回null,抛弃MessageQueue
if (mQuitting) {
dispose();
return null;
}
// 下面的代码是处理一些不紧急的任务
// 如果没有符合条件的消息,会处理一些不紧急的任务
// 每次调用MessageQueue.next(),这些代码只执行一次
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount =mIdleHandlers.size();
}
// 当执行过一次不紧急任务时,pendingIdleHandlerCount为
//0,此时不会执行下面的代码,直接开始下一步循环
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run.Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
//开始循环执行所有的IdleHandler,并且根据返回值判断是否保留
//IdleHandler
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
// IdleHandler只会在消息队列阻塞之前执行一次,执行之后改标示设
//置为0,之后就不会再执行,一直到下一次调MessageQueue.next()
//方法。
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
//当执行了IdleHandler 的 处理之后,会消耗一段时间,这时候消息
//队列里的可能有消息已经到达可执行时间,所以重置该变量回去重新检
//查消息队列。
nextPollTimeoutMillis = 0;
}
}
总的来说,MessageQueue的next()方法获取一个Message的时候,会执行下面的操作:
MessageQueue先判断消息队列中是否有同步屏障消息的存在,如果有的话,会循环取出第一个异步消息。
当MessageQueue没有可以处理的消息的时候,它会进入阻塞状态,等待新消息的到来,在阻塞之前它会执行一次 IdleHandler处理不紧急的任务,所谓的阻塞其实就是不断的循环查看是否有新的消息进入队列中。
当MessageQueue被关闭的时候,其成员变量mQuitting会被标记为true,
然后next()返回null,在Looper.loop()的源码中可以看到,当获取的message为null时,会直接return。
msg.target.dispatchMessage(msg)
msg.target.dispatchMessage(msg)主要是进行消息的分发。
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
// 1
if (msg.callback != null) {
handleCallback(msg);
} else {
// 2
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
- 1.如果msg.callback不为空,则执行handleCallback(Message),然后最终调用message.callback.run()。
- 2.如果msg.callback为空,但mCallback不为空,则执行mCallback.handleMessage(msg)。
- 3.如果msg.callback 为空,且mCallback也为空,则执行handleMessage()方法。
在大多数情况下,消息分发后的处理是第三种情况,即handleMessage(msg),这一般是通过复写该方法的方式实现消息处理的业务逻辑。
以上就是消息的取出和处理的全部内容。