深入理解Android消息处理系统——Message、Looper、Handler

来源:互联网 发布:快感增强液 知乎 编辑:程序博客网 时间:2024/06/06 17:26

        熟悉Windows编程的朋友可能知道Windows程序是消息驱动的,并且有全局的消息循环系统。而Android应用程序也是消息驱动的,按道理来说也应该提供消息循环机制。实际上谷歌参考了Windows的消息循环机制,也在Android系统中实现了消息循环机制。Android通过Looper、Handler来实现消息循环机制,Android消息循环是针对线程的(每个线程都可以有自己的消息队列和消息循环)。

1、Message的剖析

        消息队列的每个元素是Message的一个实例,其中有三个需在实现时定义:

  • what 用户定义的int类型消息代码,用来描述消息。
  • obj  随消息发送的用户指定对象(所有传递的参数对象)。
  • target 处理消息的handler类对象。
         Message的目标是Handler类的一个实例。handler可看作是“message handler”的简称。Message在创建时,会自动与一个handler相关联。Message在准备处理状态下,handler是负责让消息处理行为发生的对象。
2、Looper类剖析
        Looper类用于封装消息循环,并且有一个消息队列。Looper拥有Message对象的列队,所以Message必须在Looper上发布或读取。
        我们通常如下例子一样调用Looper类进行消息循环。
public class LooperThread extends Thread{public Handler mHandler;@Overridepublic void run() {//1、调用Looper类的prepare函数Looper.prepare();........//2、进入消息循环Looper.loop();}}//应用程序使用LooperThreadnew LooperThread().start();
        上面的代码i一共有两个关键调用(1和2两处),我们对其逐一进行分析。
        第一个调用函数是Looper的prepare函数,其代码如下:
public static void prepare() {//一个Looper只能调用一次prepare函数    if (sThreadLocal.get() != null) {        throw new RuntimeException("Only one Looper may be created per thread");    }    //构造一个Looper对象,设置到调用线程的局部变量中。    sThreadLocal.set(new Looper());}//sThreadLocal定义static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
         根据上面的分析知,prepare会在调用线程的局部变量中设置一个Looper对象。这个调用线程就是LooperThread的run线程。prepare函数主要干了一件事:在调用prepare的线程中,设置了一个Looper对象,这个Looper对象就保存在这个调用线程的TLV中。而Looper对象内部封装了一个消息列队。也就是说,prepare函数通过ThreadLocal机制,巧妙地把Looper和调用线程关联在一起了。
        第二个函数loop循环函数
public static void loop() {    final Looper me = myLooper();//myLooper返回prepare函数里保存在TLV中的Looper对象。    //取出这个Looper的消息队列    final MessageQueue queue = me.mQueue;    for (;;) {    //取出消息        Message msg = queue.next(); // might block        if(msg != null){            //Message对象中有一个target,它是Handler类型            if (msg.target == null) {//如果target为空,则表示要退出消息循环                return;            }            //调用该消息的Handler,交给它的dispatchMessage函数处理。            msg.target.dispatchMessage(msg);//注意,后面分析Handler类时会讲解到            msg.recycle();        }    }}//myLooper函数返回调用线程的线程局部变量,也就是存储在其中的Looper对象public static Looper myLooper() {    return sThreadLocal.get();}
通过上面的分析会发现,Looper的作用是:
  • 封装了一个消息队列。
  • Looper的prepare函数把这个Looper和调用prepare的线程(也就是最终的处理线程)绑定在一起了
  • 处理线程调用loop函数,处理来自该消息队列的消息。
         当事件源向这个Looper发送消息的时候,其实是把消息加到这个Looper的消息队列里了,这么该消息就将由和Looper绑定的处理线程来处理。可事件源又是怎么向Looper消息队列添加消息的呢?这就轮到Handler类登场了。
3、Handler类的分析
        Handler中所包括的成员:
final MessageQueue mQueue;//Handler中也有一个消息列队final Looper mLooper;//也有一个Looperfinal Callback mCallback;//有一个回调的类
        这几个成员变量是怎么使用的呢?这首先得分析Handler的构造函数。Handler一共有四个构造函数,它们主要的区别是在对上面三个重要成员变量的初始化上。
//构造函数1public Handler() {//获得调用线程的Looper    mLooper = Looper.myLooper();    //得到Looper的消息队列    mQueue = mLooper.mQueue;    //无callback设置    mCallback = null;    mAsynchronous = false;   }//构造函数2public Handler(Looper looper) {    mLooper = looper;//looper由外部传入,是哪个线程的Looper不确定。    mQueue = mLooper.mQueue;    mCallback = null;    mAsynchronous = false;}//构造函数3public Handler(Callback callback, boolean async) {    mLooper = Looper.myLooper();    mQueue = mLooper.mQueue;    mCallback = callback;//和构造函数1类似,只不过多了一个设置callback。    mAsynchronous = async;}//构造函数4public Handler(Looper looper, Callback callback, boolean async) {    mLooper = looper;    mQueue = looper.mQueue;    mCallback = callback;    mAsynchronous = async;}
        在上述的构造函数中,Handler中的消息队列变量最终都会指向Looper的消息队列。这样做主要是方便往Looper的消息队列里插入消息。假如,在没有Handler的情况下,只能用原始的方法往Looper的消息队列里插入消息:
  1. 调用Looper的getQueue,返回消息队列对象MessageQueue。
  2. 构造一个Message,填充它的成员,尤其是target成员变量。
  3. 调用MessageQueue的enqueueMessage,将消息插入消息队列。
        这种原始方法的确很玛法,且极容易出错(尤其是target成员变量)。但有了Handler后,我们的工作就 变得简单了。Handler提供了一系列函数帮助我们完成创建消息和插入消息队列,我们只列出其中一部分函数。
//查看消息队列是否有消息码是what的消息public final boolean hasMessages(int what) //从Handler中创建一个消息码为what的消息public final Message obtainMessage(int what)//从消息队列中移除消息码为what的消息public final void removeMessages(int what)//发送一个消息,该消息添加到队尾。public final boolean sendMessage(Message msg)//发送一个消息,该消息添加到队列首部,所以优先级很高。public final boolean sendMessageAtFrontOfQueue(Message msg) 
        下面看sendMessage函数的实现:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {    MessageQueue queue = mQueue;    if (queue == null) {        return false;    }    msg.target = this;//把Message的target设置为自己,然后加入到消息队列中    return enqueueMessage(queue, msg, uptimeMillis);}
        Handler把Message的target设为自己,是因为Handler除了封装消息添加等功能外,还封装了消息处理的接口。我们往Looper的消息队列中加入了一个消息,按照Looper的处理规则,它在获取消息后会调用target的dispatchMessage函数,再把这个消息派发给Handler处理。Handler是如何处理消息的呢?
//android/os/Handler.javapublic void dispatchMessage(Message msg) {//如果Message本身有callback,则直接交给Message的callback处理    if (msg.callback != null) {        handleCallback(msg);    } else {       //如果Handler设置了mCallback,则交给mCallback处理    if (mCallback != null) {            if (mCallback.handleMessage(msg)) {                return;            }        }    //最后才是交给子类处理,子类必须实现handleMessage方法        handleMessage(msg);    }
        dispatchMessage定义了一套消息处理的优先级机制,它们分别是:
  • Message如果自带了callback处理,则交给callback处理。
  • Handler如果设置了全局的mCallback,则交给mCallback处理。
  • 如果上述都没有,该消息则会被交给Handler子类实现的handlerMessage来处理,当初,这需要从Handler派生并重载HandleMessage函数。
        通常情况下,我们一般都是采用第三种方法,即在子类中通过重载handleMessage来完成处理工作的。
4、Looper、Message和Handler的关系
  • Looper中有一个Message队列,里面存储的是一个个待处理的Message。Looper类用于封装消息循环。
  • Message中有一个Handler,这个Handler是用来处理Message的。
  • Handler类封装了消息投递、消息处理等接口。


        Activity是一个UI线程,运行于主线程中,Android系统在启动的时候会为Activity创建一个消息队列和消息循环(Looper),在Activity中构造Handler的时候可以指定一个Looper对象,如果不指定则利用当前Activity UI线程的Looper创建Handler对象。这时,我们可以在Activity中可以创建多个工作线程或者其他的组件,如果这些工作线程或者组件把他们的消息通过刚才创建好的Handler对象放入Activity的主线程消息队列,那么该消息就会在Activity UI主线程中处理了。因为主线程一般负责界面的更新操作,并且Android系统中的weget不是线程安全的,所以这种方式可以很好的实现Android界面更新。在Android系统中这种方式有着广泛的运用。





0 0
原创粉丝点击