Android 消息机制的一点理解

android的消息系统主要包括下面几个部分:

Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。

Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。Handler的作用就是:调度消息和runnable对象去被执行;使动作在不同的线程中被执行。

MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。

Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper

Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

本质上一般的消息系统在建立时都包含以下几个部分:

|消息原型
|消息队列
|发送消息
|消息循环
|消息获取
|消息派发
|消息处理

模型图如下:


消息系统模型一般会包括以上七个部分(消息原型,消息队列,消息发送,消息循环,消息获取,

消息派发,消息处理)。实际上的核心是消息队列和消息循环,其余部分都是围绕这两部分进行的。

在Android中对这六个部分进行了抽象成四个独立的部分:

  Handler,Message,MessageQueue,Looper;

  Message就是消息原型,包含消息描述和数据,
  MessageQueue就是消息队列,
  Looper完成消息循环
  Handler就是驾驭整个消息系统模型,统领Message,MessgeQueue和Looper;

  Handler能够实现消息系统模型,那么具体是如何进行工作的呢。
要了解Handler工作原理,先看一下这个系统模型具体组成的层次结构框架是个什么样的。


Looper:
  实现Thread的消息循环和消息派发,缺省情况下Thread是没有这个消息循环的既没有Looper;
需要主动去创建,然后启动Looper的消息循环loop;与外部的交互通过Handler进行;

MessageQueue:
  消息队列,由Looper所持有,但是消息的添加是通过Handler进行;
  消息循环和消息队列都是属于Thread,而Handler本身并不具有Looper和MessageQueue;
      但是消息系统的建立和交互,是Thread将Looper和MessageQueue交给某个Handler维护建立消息系统模型。
  所以消息系统模型的核心就是Looper。消息循环和消息队列都是由Looper建立的,而建立Handler的关键就是这个Looper。 一个Thread同时可以对应多个Handler,一个Handler同时只能属于一个Thread。Handler属于哪个Thread取决于Handler在那个Thread中建立。在一个Thread中Looper也是唯一的,一个Thread对应一个Looper,建立Handler的Looper来自哪个Thread,Handler属于哪个Thread。
      故建立Thread消息系统,就是将Thread的Looper交给Handler去打理,实现消息系统模型,完成消息的异步处理。


Handler与Thread及Looper的关系可以用下面图来表示:


Handler并不等于Thread,必须通过Thread的Looper及其MessageQueue,用来实现Thread消息系统模型,依附于Thread上。

在线程建立Handler时:
  使Handler满足消息系统需要的条件,将Thread中的Looper和MessageQueue交给Handler来负责维护。
在线程中建立Handler,需要做以下工作:
  l  获取Thread中的Looper交给Handler的成员变量引用维护;
  l  通过Looper获取MessageQueue交给Handler的成员变量引用维护。
  那么消息系统模型建立完成之后,按照消息系统运行,从Handler来看就是发送消息派发消息,与此线程消息系统的交互都由Handler完成。

消息发送和派发接口:
  l  post(runnable)消息,Runnable是消息回调,经过消息循环引发消息回调函数执行;
  l  sendMessage(Message)消息,经过消息循环派发消息处理函数中处理消息;
  l  dispatchMessage       派发消息,若是post或带有回调函数则执行回调函数,否则执行消息处理函数Handler的handleMessage(通常派生类重写)。
  以上就是Handler如何实现Thread消息系统模型的大致介绍。
下面将具体分析是如何实现消息系统模型运行的。

我们知道Handler就是一个消息系统的外壳,属于某个Thread并包装了Thread的Looper及其MessageQueue;与外部进行交互(同一个线程内或者线程之间),接收派发和处理消息,消息系统模型的核心是Looper。
下面看看Handler是如何建立跑起来的,以msg消息为例,runnable实质是一样。

1 Handler的建立
 
  Handler唯一属于某个Thread,在某个Thread中建立Handler时,需要获取Thread的Looper及其MessageQueue,建立Handler关键是Looper的来源。  Handler提供了好几个构造函数但其本质一致:

由外部传入Looper:当前线程或其他线程

public Handler(Looper looper) {
        //初始化构建消息系统参数
              mLooper = looper;
              mQueue = looper.mQueue;
              mCallback = null;
  }     
从当前线程获取:由创建Handler的Thread决定

public Handler() {
        //初始化构建消息系统参数
              mLooper = Looper.myLooper();
              mQueue = mLooper.mQueue;
              mCallback = null;
  }

  public static Looper myLooper() {
        return sThreadLocal.get();
    }
我们知道Thread在默认情况下是没有建立消息循环Looper实例的。要实现消息循环必须确保Thread的Looper建立。

为了确保这一点,Looper提供了静态函数:

public static void prepare() {
     if (sThreadLocal.get() != null) {
              throw new RuntimeException("Only one Looper may be created per thread");
     }

     sThreadLocal.set(new Looper());
}

//存储线程的局部变量
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

ThreadLocal:

    维护线程的变量,为每个使用该变量的线程实例提供独立的变量副本,每个线程都能够独立使用该变量,

    而互不影响。(详细可参考:http://blog.csdn.net/qjyong/article/details/2158097

  所以每一个线程调用Looper.prepare时,都会创建为其唯一的Looper。

要建立Handler,需要先创建线程的Looper,才能建立消息系统模型。通过Looper我们建立了

Thread上的消息系统模型Handler,可以来进行消息系统的一系列流程了。

2 消息发送

消息发送两种方式:post和sendMessage;

       post:针对runnable对象;Runnable是一个接口,就是一个回调函数(提供了run方法)

       sendMessage:针对Message对象;  

       下面通过代码具体看一下这个过程:

<pre name="code" class="java">public final boolean post(Runnable r){
       return  sendMessageDelayed(getPostMessage(r), 0);
}

public final boolean sendMessage(Message msg){
    return sendMessageDelayed(msg, 0);
}

 

看到post和sendMessage发送消息时,仅仅是对象不同而已,Runnable和Message;但实际上都是Message的形式来描述。

这一点和平常接触的消息机制有点不同, 通常post消息是将消息加入到消息队列中并不立即执行就返回,send消息是立即执行等待消息执行完才返回。 而这里post或者send都是将消息放入到消息队列中,然后立即返回,等待消息循环时获取消息被执行。

这里提供了众多的消息发送方法来指定消息的执行时间和顺序,具体可以查看源代码。消息执行顺序是根据消息队列中消息的排列顺序而定。

  下面看一下发送消息后将消息加入到消息队列中的代码:

      由Handler调用MessageQueue的enqueueMessage方法:

final boolean enqueueMessage(Message msg, long when) {

              Message p = mMessages;

              if (p == null || when == 0 || when < p.when) {
                 msg.next = p;
                 mMessages = msg;
              }
              else {

                     Message prev = null;
                     while (p != null && p.when <= when) {
                            prev = p;
                            p = p.next;
                     }

                     msg.next = prev.next;
                     prev.next = msg;
              }
              ……
  }

可以看到是按照时间顺序将消息加入到MessageQueue中;

现在将消息加入到消息队列中存储起来,消息并未得到处理,下一步必然是如何派发消息和处理消息。

3 消息派发

建立Thread消息循环由Looper完成,存在一个消息调度死循环:
<pre name="code" class="java">public static void loop() {
       MessageQueue queue = me.mQueue;
       while (true) {
              Message msg = queue.next(); // might block
              if (msg != null) {
                     if (msg.target == null) {
                            // No target is a magic identifier for the quit message.
                            return;
                     }

                     //派发消息 到target(Handler)
            msg.target.dispatchMessage(msg);

            //回收Msg到msgPool
                     msg.recycle();
              }
       }
  }
 
 

这里看到消息派发是由Message的target完成,这个target是什么呢?是一个Handler。消息系统是通过Handler用来与外部交互,把消息派发出去。

消息派发由Looper通过Handler完成:

<pre name="code" class="java">public void dispatchMessage(Message msg) {

       //首先判断runnable对象
       if (msg.callback != null) {
              handleCallback(msg);
       }
       else {
              //整个消息系统的回调函数 可以不用实现自己Handler
              if (mCallback != null) {
                     if (mCallback.handleMessage(msg)) {
                            return;
                     }
              }

              //消息处理 通常交给Handler派生类
              handleMessage(msg);
       }
  }

 
 通过消息派发,这样就实现消息的异步处理。 
 

4 消息原型

post(Runnable对象),sendMessage(Message对象),而中间都是通过Message对象

保存在MessageQueue中。然后消息派发时处理方式不同。如果在sendMessage时将将消息对象

附上Runnable对象,则post和sendMessage没有区别了。所以这两种方式很好理解基本一致,处理的方式不同罢了。

下面看一下这个MessagePool是如何建立的:

  通常消息处理完毕的时候,消息也基本上处于无用状态可以释放回收了。对于需要频繁的创建释放的对象来说,

创建和释放类实例都是要开销的,太频繁的使开销增大不好,像Message这种很有可能会频繁的创建。

于是我们可以将创建的对象用完之后保存在一个Pool里面,以便再重复利用节约频繁创建释放开销。

是如何建立的呢?必然是在消息处理完毕之后才能进行。

public static void loop() {
       while (true) {
              //派发消息
              msg.target.dispatchMessage(msg);

              //消息处理完毕 回收
        msg.recycle();
    }
}     

public void recycle() {
       //回收Message 建立全局的MessagePool
       if (sPoolSize < MAX_POOL_SIZE) {
           next = sPool;
           sPool = this;
           sPoolSize++;
       }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值