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章分析。