7.4.3 分发消息到处理器
消息处理由Handler及其子类完成。首先分析Handler,代码如下:
public class Handler{
public void dispatchMessage(Message msg){
if(msg.callback!=null){//首先匹配消息中指定的回调方法
handleCallback(msg);
}else{
if(mCallback!=null){//然后匹配创建Handler时指定的回调方法
if(mCallback.handleMessage(msg)){
return;
}
}
handleMessage(msg);//最后匹配Handler的handleMessage方法
}
}
public Handler(Looper looper, Callback callback){
mLooper=looper;
mQueue=looper.mQueue;
mCallback=callback;//创建时指定回调方法
}
final Callback mCallback;
Java层的消息处理由dispatchMessage方法完成,该方法最多会做三次匹配工作,匹配成功后,将消息转发给相应的方法处理。匹配过程如下:
1)判断创建Message时是否指定了回调方法,如果已经指定回调方法,则调用handleCallback方法处理消息,通常post组方法会指定Message的回调方法。
2)判断创建Handler对象时是否在构造函数中给该Handler对象指定了回调方法,如果已指定回调方法,则调用Handler回调方法的handleMessage方法处理消息。
3)如果上述两种情况都不满足,则直接调用Handler的handleMessage方法处理消息。
接下来分析这三次匹配工作涉及的三个方法,代码如下:
public class Handler{
//对应第一次匹配
private static void handleCallback(Message message){
message.callback.run();
}
public interface Callback{//对应第二次匹配
public boolean handleMessage(Message msg);
}
public void handleMessage(Message msg){//对应第三次匹配
}
对于第一次匹配,handlerCallback方法会启动Message对象的callback线程。对于第二次匹配,Callback是一个接口,需要Callback的实现类实现其handleMessage方法。对于第三次匹配,handleMessage方法体为空,需要Handler的子类覆盖该方法。
上述三次匹配只有形式上的不同,其处理方式是类似的。这里以接口Callback的实现类FaceUnlock为例,分析消息的处理过程。FaceUnlock位于frameworks/base/policy/src/com/android/internal/policy/impl/FaceUnlock.java中,代码如下:
public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback{
public FaceUnlock(Context context,……){
……
mHandler=new Handler(this);
}
public boolean handleMessage(Message msg){
switch(msg.what){
case MSG_SHOW_FACE_UNLOCK_VIEW:
handleShowFaceUnlockView();
break;
……
default:
return false;
}
return true;
}
FaceUnlock是Handler.Callback接口的实现类之一,在其构造函数中调用了Handler的Handler(Callback callback)构造函数,该构造函数将FaceUnlock对象赋值给Handler的mCallback成员变量,因此具体的消息处理由FaceUnlock对象的handleMessage方法完成。
FaceUnlock对象在handleMessage方法中会根据Message的what成员变量指定的消息码匹配对应的函数具体处理消息。
在线程消息处理机制中,有一类特殊情况:当线程处于空闲状态时如何处理消息。
所谓线程空闲状态指的是线程满足以下两种状态:
线程的消息队列为空。
消息队列头部消息的处理时间未到。
当线程进入空闲状态时,需要执行空闲处理函数。空闲处理函数由IdleHandler指定,代码如下:
public class MessageQueue{
private final ArrayList<IdleHandler>mIdleHandlers=new ArrayList<IdleHandler>();
private IdleHandler[]mPendingIdleHandlers;//mIdleHandlers的数组形式
public static interface IdleHandler{//又是一个接口
boolean queueIdle();//Idle处理函数
}
public final void addIdleHandler(IdleHandler handler){
if(handler==null){
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized(this){//向mIdleHandlers中添加空闲处理
mIdleHandlers.add(handler);
}
}
public final void removeIdleHandler(IdleHandler handler){
synchronized(this){//空闲处理可以移除
mIdleHandlers.remove(handler);
}
}
MessageQueue内部由mIdleHandlers成员变量存储IdleHandler,并提供了addIdleHandler和removeIdleHandler两个方法,分别用来注册和删除IdleHandler。
IdleHandler是MessageQueue内部定义的一个接口,实际的空闲处理函数queueIdle由IdleHandler的实现类实现。空闲消息处理位于MessageQueue的next方法中,代码如下:
final Message next(){
int pendingIdleHandlerCount=-1;//仅当第一次循环时为-1
int nextPollTimeoutMillis=0;
for(;){
……
nativePollOnce(mPtr, nextPollTimeoutMillis);
synchronized(this){
……
final long now=SystemClock.uptimeMillis();
Message prevMsg=null;
Message msg=mMessages;
……
if(msg!=null){
if(now<msg.when){
……//消息处理时间未到,将进入空闲状态
}else{//消息需要处理,直接返回,不进入空闲状态
return msg;
}
}else{//消息为空,也将进入空闲状态
nextPollTimeoutMillis=-1;
}
//空闲处理,对应消息为空或者未到消息处理时间
if(pendingIdleHandlerCount<0
&&(mMessages==null||now<mMessages.when)){
pendingIdleHandlerCount=mIdleHandlers.size();
}
if(pendingIdleHandlerCount<=0){
mBlocked=true;//如果IdleHandler的数量为0,线程要阻塞
continue;//继续for循环,不进入空闲处理
}
if(mPendingIdleHandlers==null){
mPendingIdleHandlers=
new IdleHandler[Math.max(pendingIdleHandlerCount,4)];
}
mPendingIdleHandlers=//将mIdleHandlers转化为数组形式
mIdleHandlers.toArray(mPendingIdleHandlers);
}
for(int i=0;i<pendingIdleHandlerCount;i++){
final IdleHandler idler=mPendingIdleHandlers[i];
mPendingIdleHandlers[i]=null;//减少引用数量,防止内存泄露
boolean keep=false;
try{
keep=idler.queueIdle();//执行空闲处理函数
}catch(Throwable t){
}
if(!keep){//keep表示是否保留以执行的线程处理函数,默认不保留
synchronized(this){
mIdleHandlers.remove(idler);//执行后移除
}
}
}
pendingIdleHandlerCount=0;//重置线程处理函数数量
nextPollTimeoutMillis=0;//空闲处理状态处理完毕,此时可能已有新消息
}
}
nativePollOnce返回后,会根据消息队列的状态判断是否应该进入空闲处理状态。进入空闲处理状态后,如果此时mIdleHandlers中注册过IdleHandler,需要执行其queueIdle方法,由该方法负责线程空闲处理。IdleHandler是一个接口,其queueIdle方法需要实现类提供。
接下来以ActivityThread为例分析IdleHandler。它位于frameworks/base/core/java/android/app/ActivityThread.java中,代码如下:
public final class ActivityThread{
……
final GcIdler mGcIdler=new GcIdler();
……
final class GcIdler implements MessageQueue.IdleHandler{
public final boolean queueIdle(){
doGcIfNeeded();//空闲时判断是否GC
return false;
}
}
void scheduleGcIdler(){//将GcIdler添加到当前线程的消息队列中
if(!mGcIdlerScheduled){
mGcIdlerScheduled=true;
Looper.myQueue().addIdleHandler(mGcIdler);
}
mH.removeMessages(H.GC_WHEN_IDLE);
}
void unscheduleGcIdler(){//从当前线程的消息队列中移除GcIdler
if(mGcIdlerScheduled){
mGcIdlerScheduled=false;
Looper.myQueue().removeIdleHandler(mGcIdler);
}
mH.removeMessages(H.GC_WHEN_IDLE);
}
空闲消息处理函数用于在线程暂时无消息处理时做一些辅助工作,其重要应用之一是在GcIdler中完成空闲时内存垃圾回收,其另外一个重要应用是,在Home启动后进入空闲状态时发送BOOT_COMPLETED广播,这部分内容将在第11章分析。