您的位置:首页 > 移动开发 > Android开发

Android消息机制源码解析(二)——消息的执行者Handler

2015-12-14 13:22 519 查看
这一节来分析Handler的源码实现,Handler从字面理解就是处理程序、处理器的意思,在Android消息机制中它扮演着执行者的角色,消息的发送、接收、处理都是由Handler来完成的,它也是跟开发者打交道最多的,因此我们更有必要深入了解Handler的实现原理。

一、首先是Handler类的定义:

public class Handler
Handler有以下几个主要属性字段:

final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
final boolean mAsynchronous;
IMessenger mMessenger;
mQueue是一个MessageQueue对象,第一节讲Message的时候提到过,发送的消息会放到一个消息队列里面,就是它了,第四节会详细讲解MessageQueue;mLooper是一个Looper对象,可以理解为一个循环器,它不断从消息队列中将消息取出来,交给Handler处理,第三节也会详细分析其实现原理,暂时理解它的作用就行;mCallBack是Handler中定义的一个CallBack接口,下文会讲起具体作用;mAsynchronous表示是否为异步处理的布尔值,一般在调用Handler的构造函数时会给其赋值,默认都为false,如果设置为true,其本质会调用第一节中Message的setAsynchronous(boolean)方法,将消息设为异步消息;mMessenger是用来进程间通信的,本文暂不作过多解释。

二、再来看Handler的构造函数,源码中共提供了7个无参或有参的构造函数,罗列如下:

public Handler()
public Handler(Callback callback)
public Handler(Looper looper)
public Handler(Looper looper, Callback callback)
public Handler(boolean async)
public Handler(Callback callback, boolean async)
public Handler(Looper looper, Callback callback, boolean async) 
上述几个构造函数,你可以根据需求使用任何一个来创建Handler实例,需要注意的是一个Handler必须要对应一个Looper。一个线程中只能有一个Looper,但可以有多个Handler,虽然有的构造函数没有Looper参数,那是因为在主线程中使用Handler时不需要开发者自己创建Looper,ActivityThread已经为我们创建好了,具体源码在ActivityThread的main()方法中,有兴趣的可以去验证一下。如果在子线程中创建Handler对象,则必须要提供Looper对象,至于Looper怎样创建,在下一节会详细说明。其他参数如CallBack及异步标识async就很好理解了。

三、接下来是Handler的obtainMessage()系列方法:

public final Message obtainMessage()
public final Message obtainMessage(int what)
public final Message obtainMessage(int what, Object obj)
public final Message obtainMessage(int what, int arg1, int arg2)
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
这一系列方法内部实质上是调用Message的obtain()系列方法,从消息池中获取一个Message,在第一节也提到过。

四、下面是最重要的发送消息环节了,可以利用Handler发送Runnable或Message,且各自对应一系列同名方法,如发送Runnable的方法主要有:

public final boolean post(Runnable r)
public final boolean postAtTime(Runnable r, long uptimeMillis)
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
public final boolean postDelayed(Runnable r, long delayMillis)
public final boolean postAtFrontOfQueue(Runnable r)
从上述函数名可以很好理解其含义,postAtTime()表示在某个特定时间点发送;postDelayed()表示延迟多久发送消息;postAtFrontOfQueue()表示将消息插入到队列头部。

发送一个Runnable时,实质上会将Runnable转换成一个Message对象。还记得第一节分析Message时的Runnable callback字段吗?正是通过构造一个Message对象,将所发送的Runnable赋值给了Message的callback字段,详细代码如下:

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}
发送Message的一系列方法为:

public final boolean sendMessage(Message msg)
public final boolean sendEmptyMessage(int what)
public final boolean sendEmptyMessageDelayed(int what, long delayMillis)
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis)
public final boolean sendMessageDelayed(Message msg, long delayMillis)
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
public final boolean sendMessageAtFrontOfQueue(Message msg)
前边几个方法最终会调用到sendMessageAtTime(),来看一下其具体实现:

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, msg, uptimeMillis)方法,顾名思义,就是将该消息添加到队列中。来看下这个方法的具体实现:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}
如果构造Handler时,设置了async参数为true,则会调用消息的msg.setAsynchronous(true)方法,最终的入队操作实际上是在MessageQueue中实现的,第四节会详细分析。

postAtFrontOfQueue(Runnable r)最终会调用sendMessageAtFrontOfQueue(Message msg),内部也会调用enqueueMessage(queue, msg, uptimeMillis)方法进行入队操作,只不过uptimeMillis值为0,这样就可以将消息放到队列头部,顺便提一下,这里的uptimeMillis对应着Message里的when字段。

五、既然Handler可以发送Runnable和Message,因此它还提供了相关的删除方法:

public final void removeCallbacks(Runnable r)
public final void removeCallbacks(Runnable r, Object token)
public final void removeMessages(int what)
public final void removeMessages(int what, Object object)
public final void removeCallbacksAndMessages(Object token)
其内部实现都是一样的,都是调用MessageQueue的相关删除方法,将消息从队列中移除,详细内容待第四节分析。

六、消息发送和删除已经分析完了,接下来就是消息接收和处理了,先看相关源码:

/**
 * Callback interface you can use when instantiating a Handler to avoid
 * having to implement your own subclass of Handler.
 *
 * @param msg A {@link android.os.Message Message} object
 * @return True if no further handling is desired
 */
public interface Callback {
    public boolean handleMessage(Message msg);
}

/**
 * Subclasses must implement this to receive messages.
 */
public void handleMessage(Message msg) {
}

/**
 * Handle system messages here.
 */
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}
第一个是Callback接口的定义,看注释可以知道,在某些情况下如果不想实现Handler的子类,则可以通过实现该接口来处理收到的消息。

第二个是handleMessage(Message msg),这个方法是个空方法,需要在子类实现具体的处理逻辑,我们一般多采用这种方法,创建一个Handler子类,通过重写handleMessage(Message msg)方法来实现自己的消息处理逻辑,当然上述两种方法都是可以的,看自己的需要了。

第三个是dispatchMessage(Message msg)了,也就是消息处理的逻辑。它的执行过程为,如果该消息有callback(也就是之前提到的Runnable对象),则响应callback,具体实现为:

private static void handleCallback(Message message) {
    message.callback.run();
}
接下来判断是否实现了自定义的Callback接口,如果实现了则响应该接口回调,如果没有,则响应子类的handleMessage(msg)方法。

需要特别注意的是handleMessage(Message msg)是在Looper中被调用的,前面简单介绍过,Looper可以理解为消息循环器,作用是不断从MessageQueue中取出消息,交给Handler处理,就是调用了这个方法。因为一个线程只能有一个Looper,如果该Handler是在主线程创建的,那么Looper也是运行在主线程的,同样handleMessage(Message msg)也就运行在主线程了,我们常用的使用Handler消息机制更新UI就是这个原理。

Handler的主要内容就是这些,比较容易理解,下一节会继续分析Looper,请关注《Android消息机制源码解析(三)——消息循环器Looper》。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息