Android开发 之 理解Handler、Looper、MessageQueue、Thread关系

 

本文转自博客:http://blog.csdn.net/he90227/article/details/43567073

 

 

一. 图解与概述

 

首先Android中 的每一个线程都会对应一个MessageQueue和Looper。见名知意,MessageQueue即线程用来维护线程产生的消息的消息队列,而这个 队列的调度则是由Looper来完成的。Looper负责将产生的消息放入队列,并及时的将合适的消息从队列中取出并交由合适的接受者处理。处理消息的便 是每个线程内部的Handler对象,特别是在UI线程中,由于Handler与UI处于同一个线程,所以我们就可以通过Handler处理接收到的消息 并及时更新UI中的组件。

 

上述描述即可以实现在其它线程中完成耗时操作并在UI线程中通过Handler更新组件以反映耗时操作的处理效果。

以下是它们之 间关系的图示:



理解概念:

Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。
MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。
Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

 

简单关系:


 

Handler,Looper和MessageQueue就是简单的三角关系。

Looper和MessageQueue一一对应,线程和looper也是一一对应,创建一个Looper的 同时,会创建一个MessageQueue。

而Handler与它们的关系,只是简单的聚集关系,即Handler里会引用当前线程里的特定Looper 和MessageQueue。
这样说来,多个Handler都可以共享同一Looper和MessageQueue了。

当然,这些Handler也就运行在同一个线程里。

 

 

消息循环过程:

生成消息

1 Message message = handler.obtainMessage();  
2 message.arg1 = id;  
3 message.obj = drawable;  
4 handler.sendMessage(message);  

发送消息

 
 1      /** 
 2      * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> 
 3      * to this handler. 
 4      * @param uptimeMillis The absolute time at which the message should be 
 5      *         {@link android.os.SystemClock#uptimeMillis} time-base. 
 6      * @return Returns true if the message was successfully placed in to the  
 7      *         looper processing the message queue is exiting.  Note that a 
 8      *         the looper is quit before the delivery time of the message 
 9      */  
public boolean sendMessageAtTime(Message msg, uptimeMillis)
10 { 11 sent = ; 12 MessageQueue queue = mQueue; 13 (queue != ) { 14 msg.target = ; 15 sent = queue.enqueueMessage(msg, uptimeMillis); 16 } 17 { 18 RuntimeException e = RuntimeException( 19 + , e.getMessage(), e); 20 } 21 sent; 22 }

 

 在 Handler.java的sendMessageAtTime(Message msg, long uptimeMillis)方法中,我们看到,它找到它所引用的MessageQueue,然后将Message的target设定成自己(目的是为了在 处理消息环节,Message能找到正确的Handler),再将这个Message纳入到消息队列中。

 

Looper从消息队列中抽取消息

/** 
 1      public  static final void  loop() {  
 2         Looper me = myLooper();  
 3         MessageQueue queue = me.mQueue;  
 4          () {  
 5             Message msg = queue.next();   
 6               
 7               
 8               
 9              (msg != ) {  
10                  (msg.target == ) {  
11                       
12                     ;  
13                 }  
14                  (me.mLogging!= ) me.mLogging.println(  
15                                              );  
16                 msg.target.dispatchMessage(msg);  
17                  (me.mLogging!= ) me.mLogging.println(  
18                                             + msg.callback);  
19                 msg.recycle();  
20             }  
21         }  
22     }  

 

 在Looper.Java的loop()函数里,我们看到,这里有一个死循环,不断地从MessageQueue中获取下一个(next方法)Message,然后通过Message中携带的target信息,交由正确的Handler处理(dispatchMessage方法)。

处理

 
 1     /** 
 2      * Handle system messages here. 
 3      */  
 4     public void dispatchMessage(Message msg) {  
 5         if (msg.callback != null) {  
 6             handleCallback(msg);  
 7         } else {  
 8             if (mCallback != null) {  
 9                 if (mCallback.handleMessage(msg)) {  
10                     return;  
11                 }  
12             }  
13             handleMessage(msg);  
14         }  
15     }  

 

在 Handler.java的dispatchMessage(Message msg)方法里,其中的一个分支就是调用handleMessage方法来处理这条Message,而这也正是我们在职责处描述使用Handler时需要 实现handleMessage(Message msg)的原因。

至于dispatchMessage方法中的另外一个分支,我将会在后面的内容中说明.

 

至此,我们看到,一个Message经由Handler的发送,MessageQueue的入队,Looper的抽取,又再一次地回到Handler的怀抱。而绕的这一圈,也正好帮助我们将同步操作变成了异步操作。

Handler所处的线程及更新UI的方式

在 主线程(UI线程)里,如果创建Handler时不传入Looper对象,那么将直接使用主线程(UI线程)的Looper对象(系统已经帮我们创建 了);在其它线程里,如果创建Handler时不传入Looper对象,那么,这个Handler将不能接收处理消息。在这种情况下,通用的作法是:

 
 1  class LooperThread extends Thread {  
 2       public Handler mHandler;  
 3       public void run() {  
 4             Looper.prepare();  
 5             mHandler = new Handler() {  
 6                public void handleMessage(Message msg) {  
 7                // process incoming messages here  
 8                }  
 9             };  
10             Looper.loop();  
11       }  
12 } 

 

在创建Handler之前,为该线程准备好一个Looper(Looper.prepare),然后让这个Looper跑起来(Looper.loop),抽取Message,这样,Handler才能正常工作。
因此,Handler处理消息总是在创建Handler的线程里运行。而我们的消息处理中,不乏更新UI的操作,不正确的线程直接更新UI将引发异常。因此,需要时刻关心Handler在哪个线程里创建的。

 

     1,MessageQueue与Message的关系

Message中文是消息,及线程处理的最小单元,里面带有处理的数据集,或还带有操作,及告诉目的地要做什么事情,   每个MessageQueue里包含有Message。每个Message不是直接插入到MessageQueue里的,而是通过MessageQueue.IdleHandler 与looper一起工作,把Message放到MessageQueue里,及addIdleHandler(MessageQueue.IdleHandler handler) 和removeIdleHandler(MessageQueue.IdleHandler handler) 方法,把MessageQueue.IdleHandler压入到MessageQueu里。

 

        2,Thread和HandlerThread的关系

        HandlerThread就是带有Looper循环的Thread.

 

        3,Looper介绍

        Looper即一个循环,必须绑定到一个固定的线程里,通过getThread()方法可以获得该looper绑定的Thread对象,通过 getMainLooper()获得主线程里的looper对象,myLooper()可以获得当前线程里的looper对象,通过myQueue()方 法可以获得当前线程里的messageQueue对象。

       

        4,Thread、HandlerThread、和Looper的关系的关系

        一般声明一个thread是没有带looper循环的,但是可以通过Looper.prepare()方法给一个线程加上 looper;Looper.loop()执行该looper绑定的线程里的messageQueue,直到该loopger结 束;Loop.quit()结束该循环,实例代码如下:


 1  class LooperThread extends Thread {
 2       public Handler mHandler;
 3       
 4       public void run() {
 5           Looper.prepare();
 6           
 7           mHandler = new Handler() {
 8               public void handleMessage(Message msg) {
 9                   // process incoming messages here
10               }
11           };
12           
13           Looper.loop();
14       }
15   }

     

    5,Handler和Thread HandlerThread Looper Message MessageQueue的关系

它把消息发送到该生成它的线程里的MessageQueue里,然后当Message出队列的时候,就执行该消息。
post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long),是用来处理runnable对象的;
sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long), and sendMessageDelayed(Message, long)方法是
可以通过handleMessage (Message msg) 方法来接收消息。
实例化:Handler(Looper looper) 



 

二. 多线程与异步

Main Thread & UI Thread

当程序启动的时候android会自动创建一个进程和一个线程,这个线程负责界面更新,收集系统事件和用户的操作事件等并分配给对应的组件,所以这个线程非常重要 被称为主线程,因为所的和UI有关的操作都是在这个线程当中进行的所以也被称作UI线程。所以说默认情况下主线程和UI线程指的是同一个线程。

Android的UI系统参考了很多SWT的设计模式。比如,UI线程机制,底层JNI实现 etc.

Android 的UI系统是非线程安全的,意思是说只有创建UI的线程(也就是主线程)才可以对UI进程操作。如果我们在其它线程中执行了一些操作,而这些操作的结果又需要通过UI展现给用户,必需把这更新UI的操作转移到到UI线程中执行。

很多Java起步的程序员对UI线程中的"消息循环"会感觉陌生。其实就是在线程内部有一个死循环一直监听系统事件(用户的操作等)并把任务分发给对应的 组件(有兴趣的可以看看NDK附带的native-activity的一个sample,在c中的实现方式就是一个while(1)的死循环)。主线程通 过Looper实现了消息的循环处理。

The ralationship between Handler,Message,MessageQueue and Looper?

如果一个线程里边有一个死循环,那么这个循环就会一直在死循环里边循环,并且这个线程不会过多的cpu资源,那么这个线程肯定的阻塞的。如果线程只是一直 循环没有什么意义,实际情况通常需要线程根据不同的条件运行不同的方法。我们通常的作法可能会加一个switch开关,根据条件的不同去调用不同的方法。

线程间通信(最常见的就是,worker线程需要更新UI),这个时候实际是包含两个内容:一,数据的传递;二,方法的传递; Android中的Message用于数据传递,而Handler就是方法传递(其实是方法的执行者,Handler会把这个方法放到Handler所在 的线程当中去执行);MessageQueue是Message的容器和Java中的Queue一样都是容器,只不过Message Queue是专门用于装载Message的容器。Looper则是一个线程中的死循环用于管理MessageQueue,它负责阻塞读取 MessageQueue中的信息(如果MessageQueue中没有信息会一直在那里),挨个读取并把这个Message分发给对应的Handler 去执行。

 

首先看一下mHandler.obtainMessage(SHOW_ALERT, Greetings).sendToTarget();会执行什么。

通过查看Handler的源码发现执行了下边的代码。

1 public final Message obtainMessage(int what, Object obj){
2     return Message.obtain(this, what, obj);
3 }
 
 
 接着查看Message中的代码
 1 public static Message obtain(Handler h, int what, Object obj) {
 2     Message m = obtain();
 3     m.target = h;
 4     m.what = what;
 5     m.obj = obj;
 6     return m;
 7 }
 8 /**
 9 * Return a new Message instance from the global pool. Allows us to
10 * avoid allocating new objects in many cases.
11 */
12 public static Message obtain() {
13     synchronized (mPoolSync) {
14         if (mPool != null) {
15             Message m = mPool;
16             mPool = m.next;
17             m.next = null;
18             return m;
19         }
20     }
21     return new Message();
22 }

 

  看到这里我们应该明白为什么Google建议我们使用obtainMessage而不是new一个Message.这也是符合了Android中的对象回收机制。

 1 public void sendToTarget() {
 2 
 3     target.sendMessage(this);//targe就是一个Handler
 4 
 5 }
 6 sendMessage()会调用下面的sendMessageAtTime()把Message加入MessagQueue;
 7 
 8 public boolean sendMessageAtTime(Message msg, long uptimeMillis){
 9     boolean sent = false;
10     MessageQueue queue = mQueue;
11     if (queue != null) {
12         msg.target = this;
13         sent = queue.enqueueMessage(msg, uptimeMillis);
14     }else {
15         RuntimeException e = new RuntimeException(
16                 this + " sendMessageAtTime() called with no mQueue");
17         Log.w("Looper", e.getMessage(), e);
18     }
19     return sent;
20 }

 到此我们的Message对象被加入到了Handler所在线程(也就是主线程)中的MessageQueue这个存储和管理Message的容器当中。下一步就该由Looper接手一个一个的取出Message对象处理了。Looper最主要的方法就是loop()方法

 

 1 public static final void loop() {
 2     Looper me = myLooper();
 3     MessageQueue queue = me.mQueue;
 4     while (true) {//死循环
 5         Message msg = queue.next(); // might block
 6            if (msg != null) {
 7             if (msg.target == null) {//退出死循环的机制
 8             // No target is a magic identifier for the quit message.
 9         return;
10         }
11          if (me.mLogging!= null) me.mLogging.println(
12             ">>>>> Dispatching to " + msg.target + " "
13                  + msg.callback + ": " + msg.what
14         );
15         msg.target.dispatchMessage(msg);//target of a msg is a Handler
16         if (me.mLogging!= null) me.mLogging.println(
17              " Finished to    " + msg.target + " "
18             + msg.callback);//msg.callback is a Runnable
19             msg.recycle();
20         }
21     }
22 }

 Looper会一直阻塞读取MessagQueue中的Message对象(Message msg = queue.next()),当读取到一个Message时就会调用msg.target.dispatchMessage(msg)把这个 Message分发给对应的Handler去处理,等Handler把任务处理完了再接着读取下一个Message对象并处理。

 1 /**
 2 * Handle system messages here.
 3 */
 4 public void dispatchMessage(Message msg) {
 5     if (msg.callback != null) {
 6         handleCallback(msg);// call the run method of the runnable object I guess
 7     } else {
 8         if (mCallback != null) {
 9             if (mCallback.handleMessage(msg)) {
10             return;
11             }
12         }
13         handleMessage(msg);
14     }
15 }

 最后回来了我们的handlerMessage(msg);这个方法中。如果是用的不是sendMessage是是Hadler.post(Runnable)会调用


1 private final void handleCallback(Message message) {
2     message.callback.run();
3 }

这就是为什么在Handler中post的Runnable不会开启一个新的线程的原因。经过上面的追踪我们应该能明白不是所有 的线程都可以有Handler去执行handlerMessage或者处理Runnalbe的。其必要条件就是这个线程要有一个一直循环的 Looper.Looper一直循环肯定要有一个方法可以退出循环。

 

Thread,Looper,Handler,Message,MessageQueue之间的关系 - Gobby.X - Just Miss.Gobby

当我们调用msg.sendToTarget()的时候,我们的msg对象应付被压入MessageQueue的尾部。Looper在 MessageQueue的另一端一个一个的读取信息并处理。根据msg的target属性把cpu分配给对应的Handler去执行任务,这时 Handler会根据msg中的属性调用msg.handleMsg()或者msg.callback.run();当一个msg中的消息处理完返回之后 Looper会把这个msg放入msgPool当中方便下次再重复利用。从而减少对象的创建。Looper再从MessageQueue中读取下一个信 息,如此反复。。

理解了这些其实就不难想象ANR是如何实现的了。当用户执行操作(比如点击了一个按钮)系统会生成一个Message对象,把用户操作的信息写入 Message对象,并把这个Message对象压入MessageQueue队列的尾部。系统过一段时间(一般是五秒)后会再来检查,刚刚放入的信息是 不是已经被处理了,如果信息还在队列中就表明。处理前面信息的过程当中发生的阻塞,用户的操作没有及时得到响应。系统弹出ANR对话框。

 

作个总结:

  因为UI线程需要保持一直运行的状态,所以要有一个循环保持这个线程不会死掉,但这个线程又必需阻塞,以减少cpu的消耗。android中的这个循 环就是通过Looper实现的。有了这个 Looper,Looper就占据了整个线程,导致所有的方法想在些线程中运行就必需通过这个Looper,所以要有个方法可以进入这个Looper的内 部。MessageQueue就担当了这个通道 的角色。Message担当了集合的角色。所有在UI线程中运行的方法都必需通过MessageQueue进入Looper内部,不管 是用户定义的方法还是系统事件包括onCreate(),onStop(),用户点击事件etc..

 

 

三.Android中消息系统模型和Handler Looper

消息系统的基本原理和构成

       从一般的消息系统模型的建立大致构成以下几个部分:

    l  消息原型

    l  消息队列

    l  发送消息

    l  消息循环

    l  消息获取

    l  消息派发

    l  消息处理

 

大致模型图如下:

    

 

       消息系统模型一般会包括以上七个部分(消息原型,消息队列,消息发送,消息循环,消息获取,消息派发,消息处理)。实际上的核心是消息队列和消息循环,其余部分都是围绕这两部分进行的。

  从前面文档的分析中我们知道Handler就是用来建立消息处理的系统模型,那么和这里基本消息系统模型相比,那么Handler又是如何囊括这七个部分的呢?

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

    Handler,Message,MessageQueue,Looper;

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

 

 Handler能够实现消息系统模型,那么具体是如何进行工作的呢,下面探究一下这其中工作的方法和原理。

 

 

 

 

四. Handler工作原理分析

  要了解Handler工作原理,先看一下这个系统模型具体组成的层次结构框架是个什么样的。

 

      

 

  实现Thread的消息循环和消息派发,缺省情况下Thread是没有这个消息循环的既没有Looper;需要主动去创建,然后启动Looper的消息循环loop;与外部的交互通过Handler进行;消息队列,由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实现流程分析

 

  我们知道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>();
复制代码

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

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

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

 

2 消息发送


 

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

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

       sendMessage:针对Message对象;

       

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

复制代码
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方法:

       

 1 final boolean enqueueMessage(Message msg, long when) {
 2 
 3               Message p = mMessages;
 4 
 5               if (p == null || when == 0 || when < p.when) {
 6                  msg.next = p;
 7                  mMessages = msg;
 8               }
 9               else {
10 
11                      Message prev = null;
12                      while (p != null && p.when <= when) {
13                             prev = p;
14                             p = p.next;
15                      }
16 
17                      msg.next = prev.next;
18                      prev.next = msg;
19               }
20               ……
21   }

 

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

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

 

3 消息派发


 

建立Thread消息循环由Looper完成,存在一个消息调度死循环:    

复制代码
  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用来与外部交互,把消息派发出去。可以看到没有这个Handler,消息循环将结束。

 

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

复制代码
  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没有区别了。所以这两种方式很好理解基本一致,处理的方式不同罢了。

  消息系统模型中,我们的真正的消息原型是什么,都具有那些功能,下面看一下Message中到底包含了那些东西,能有效帮助我们合理的运用消息系统来完成一些任务和处理。

Message消息原型:

复制代码
  public final class Message implements Parcelable {
         //标识消息
         public int what;
         int flags;
         long when;
      
         //传递简单数据
         public int arg1;
         public int arg2;
    
         //传递较复杂数据 对象
         public Object obj;
         Bundle data;

         //处理消息的目标Handler
         Handler target;   

         //消息派发时 执行的Runnable对象
         Runnable callback;  

         //使消息形成链表
         Message next;

         //建立一个消息pool,回收msg,以避免重复创建节约开销
         private static Message sPool;
         private static int sPoolSize = 0;
         private static final int MAX_POOL_SIZE = 10;
  }  
复制代码

  

  看到提供了很丰富的属性来描述消息,针对具体问题选择使用那些属性去怎么样描述消息了。

  获取新的Message对象时,Message提供了obtain方法:避免我们自己去分配Message新的对象,通过obtain获取,可能从MessagePool中获取,节约开销。

 

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

  通常消息处理完毕的时候,消息也基本上处于无用状态可以释放回收了。对于需要频繁的创建释放的对象来说,创建和释放类实例都是要开销的,太频繁的使开销增大不好,像Message这种很有可能会频繁的创建。

 

  于是我们可以将创建的对象用完之后保存在一个Pool里面,以便再重复利用节约频繁创建释放开销。是如何建立的呢?必然是在消息处理完毕之后才能进行。

MessagePool建立:

复制代码
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++;
       }
}
复制代码

 

 

六. Handler的应用

  以上这就是整个Handler作用及消息系统模型的建立。

使用也非常简单,虽然有很多方式,但只要理解Handler是建立在Looper上,实现Thread的

消息系统处理模型,实现消息异步处理,我想对与Handler基本应用上没有什么不能理解的了。

其他方面可以去看源码了。

  Handler使用起来是非常简单的,关键就是如何利用消息的异步处理,来合理的完成我们

需要功能和任务。对于一个Thread,我们使用好几个Handler来进行异步处理,也可以创建新的Thread,

通过Handler来实现消息异步处理等等,应用场景很多如何用的好用的合理,这就没什么经验了。

  至于如何使用,源码中很多例子可以看一下AsyncQueryHandler这个类,其中两个线程,

完成查询工作,通过Handler进行线程之间有消息传递。感觉这个利用的很好很巧妙。

 

posted @ 2017-06-15 15:02  浪里小白龙呼呼呼  阅读(1221)  评论(0编辑  收藏  举报