Android消息机制

Android的消息机制主要是指Handler的运行方式。
对于Android开发者而言,Handler并不陌生,它常常被用来向主线程post消息,更新UI等操作。日常开发中只需和Handler类交互即可,然而,稍微深入了解Handler运行机制可以让开发者更加熟悉Android系统消息机制,做到运用自如。
Handler的运行需要MessageQueue和Looper的支撑。MessageQueue保存消息,提供消息队列的实现;Looper实现线程循环处理消息和分发;其他线程通过Handler对象可以向Looper线程发送消息(该消息最终由创建Handler的线程负责处理),Handler MessageQueue和Looper三者工作关系大致如下:
这里写图片描述

1.MessageQueue

该类是消息队列实现类,消息实体由Message类实现。在MessageQueue类中维护着一个Message链表(虽然取名为队列,其实现是单向链表),其核心操作是向消息队列添加消息以及获取消息,分别对应于方法enqueueMessage()和next()。
enqueueMessage方法原型如下:

 boolean enqueueMessage(Message msg, long when) {
     //单向链表同步插入
 }

next方法即是从链表中获取一条消息并返回给调用者,同时将该条消息从链表中删除;
MessageQueue的逻辑并不复杂,需要了解的基本操作就是插入和获取,很清晰。

2.Looper

Looper类的核心职能是循环读取消息队列中的消息,并分发出去。

Looper构建
Looper类核心变量:

 // sThreadLocal.get() will return null unless you've called prepare().
 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

 final MessageQueue mQueue;
 final Thread mThread;

其中sThreadLocal 是线程私有变量,为每个创建Looper的线程保存其创建的Looper对象;
mQueue是消息队列;
mThread是创建Looper的线程;
在Looper对象的构造方法中会初始化消息队列:

   private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
   }

从上面代码片段可知Looper的构造函数是私有的,因此,Looper对象的构建并不是手动创建的。从源码可以得知,通过静态方法 prepare() 可以为当前线程创建Looper对象,同时在Looper的创建中又会创建消息队列。因此,在使用时只需在当前线程内调用Looper.prepare(),即可完成Looper对象和消息队列的构建,示例如下:

new Thread("#SubThread"){
    @Override
    public void run() {
        Looper.prepare();
    }
}.start();

这样即可给线程”#SubThread”构建Looper和MessageQueue(当然仅仅是给Handler的使用创建必须的消息队列和循环机制,仅这样不能构建消息机制)。Looper还为主线程单独提供prepareMainLooper()方法(内部调用prepare方法),并保存主线程的Looper对象且提供获取主线程Looper的方法getMainLooper()。

开启消息循环
构建Looper之后必须调用loop()方法,手动开启消息循环。为线程构建消息队列的完整步骤如下:

new Thread("#SubThread"){
    @Override
    public void run() {
        Looper.prepare();
        Handler handler = new Handler();
        Looper.loop();
    }
}.start();

分析源码可知,loop方法是一个死循环,不断地从消息队列中获取消息(如果队列暂时没有消息,则阻塞直至有线程向消息队列添加消息为止),并将消息分发。
至此 线程”#SubThread”已构建消息队列,并开启消息循环。其它线程通过handler即可向线程”#SubThread”发送消息。

3.Handler

Handler类是消息机制中最常被开发者使用。常见的情况是在UI线程(主线程)中使用Handler,子线程通过Handler对象完成更新UI等操作,而无须接触MessageQueue和Looper。究其原因是主线程在启动过程中已完成MessageQueue和Looper的创建,以下是ActivityThread类main方法的代码片段:

 public static void main(String[] args) {
       //省略多行代码
        Looper.prepareMainLooper();

        //省略多行代码

        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

可见,在主线程启动过程中,已经构建消息队列并开启消息循环,因此,在主线程中,我们可以方便的使用Handler,而无须关心其对应得Looper和MessageQueue。但是,为了更好理解消息机制,了解Handler是如何与Looper和MessageQueue协同工作还是有必要的。

Handler的创建
如上方式Handler handler = new Handler();创建Handler对象最终会调用下边的构造方法:

 public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

代码逻辑很清晰,如果是在没有构建Looper的线程内调用此构造方法会抛出运行时异常,并提示“不可以在未调用Looper.prepare()方法的线程内创建Handler对象”;创建过程中handler会保存Looper中消息队列的引用,便于后续的消息添加。

通过Handler发送消息
通过调用Handler类提供的sendMessage系列方法可以发送消息,不同类型的sendMessage方法发送的消息内容设置稍有不同,以一条空消息为例,如下调用即可:

handler.sendEmptyMessage(MSG_TEST);

方法经过几次传递最终会调用enqueueMessage方法,该方法是Handler发送消息的实际操作部分,代码如下:

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

该方法其实也不是真正干活的,它调用MessageQueue的enqueueMessage方法向消息队列中添加一条消息。
因此通过Handler发送消息的逻辑最终归结为向MessageQueue消息链表内添加一条消息。

发送的消息如何传递至handleMessage()方法
一般在构建Handler对象时,我们会重写handleMessage方法,在该方法内处理各个不同类别的信息,典型逻辑如下:

 Handler handler = new Handler(){
      @Override
      public void handleMessage(Message msg) {
          switch (msg.what){
             case MSG_ONE:
                 handleMsgOne();
                 break;
             case MSG_TWO:
                 handleMsgTwo();
                 break;
             default:
                 break;
          }
     }
};

那么经由handler 调用sendMessage的消息是如何被传递至handleMessage方法内的呢?
上一段,我们讲到sendMessage最终是在消息队列中添加一条消息记录,而是谁在不断读取并分发消息队列中的消息呢?没错就是Looper。Looper所在的线程调用loop()方法之后便在不断的从消息队列中读取消息并分发,其关键代码片段如下:

    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

       //省略多行

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            //省略多行

            msg.target.dispatchMessage(msg);

            //省略多行

            msg.recycleUnchecked();
        }
    }

loop方法的逻辑也比较清晰:调用MessageQueue的next()方法获取一条消息,调用消息对象msg的target字段的dispatchMessage方法分发消息;
那么,分发消息应该就是由,这个msg所对应的target来处理了。
Message类中target字段定义/*package*/ Handler target;
可知,target是一个Handler对象,而在sendMessage的过程中的最终函数enqueueMessage(代码见上文)中有关键的一句:

 msg.target = this;

即将msg的target对象指向了发送msg的handler,因此,dispatchMessage最终还是由发送msg的Handler对象处理。
Handler的dispatchMessage方法如下:

 public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

终于,在这里调用了hanleMessage()方法,把消息处理的最终实体回调给Handler的定义者(hanleMessage()默认为空实现)。

看到这里,相信读者对Android的消息机制有一定的了解了。
那么有同学可能会问了,Handler内先通过sendMessage添加消息,再经由Looper回调handleMessage()方法,兜一圈不累吗?
Android系统的设计者们估计会说,累但很有必要。细心的读者会发现,调用sendMessage 和回调handleMessage的线程是不同的。sendMessage可以在任何子线程内通过handler对象发送,而回调handleMessage的线程是当初创建Handler ,Looper和MessageQueue的线程。这也就是为什么我们常常在主线程内创建Handler对象,重写相应的handleMessage()逻辑并且可以在此更新UI,而各子线程内一般只能通过这个Handler对象发送消息。
Handler,MessageQueue和Looper三者的配合构成了Android系统的消息机制,提供了一种线程通信实现方式,它在Android FrameWork 可以经常看到,使用简单(尤其是也主要是在UI线程和子线程通信的情况中),希望大家通过这篇文章可以对它有更好的了解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值