理解Handler、Looper、MessageQueue、Thread关系?一

来源:互联网 发布:算法的五个特征 编辑:程序博客网 时间:2024/04/29 05:22

图解

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



概览

转载请注明:http://blog.csdn.net/richway2010/article/details/6582818

【博主:各位博友,网友们,大家网上好!欢迎光临本博客。 欢迎多多交流,多提意见,互相学习,互相进步,我们的口号是:好好学习,天天向上。】

理解概念:

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的同时,会创建一个MessageQueue。而Handler与它们的关系,只是简单的聚集关系,即Handler里会引用当前线程里的特定Looper和MessageQueue。
这样说来,多个Handler都可以共享同一Looper和MessageQueue了。当然,这些Handler也就运行在同一个线程里。

消息循环过程:

生成消息

[java] view plaincopyprint?
  1. Message message = handler.obtainMessage();  
  2. message.arg1 = id;  
  3. message.obj = drawable;  
  4. handler.sendMessage(message);  

发送消息

[java] view plaincopyprint?
  1. /** 
  2.  * Enqueue a message into the message queue after all pending messages 
  3.  * before the absolute time (in milliseconds) <var>uptimeMillis</var>. 
  4.  * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> 
  5.  * You will receive it in {@link #handleMessage}, in the thread attached 
  6.  * to this handler. 
  7.  *  
  8.  * @param uptimeMillis The absolute time at which the message should be 
  9.  *         delivered, using the 
  10.  *         {@link android.os.SystemClock#uptimeMillis} time-base. 
  11.  *          
  12.  * @return Returns true if the message was successfully placed in to the  
  13.  *         message queue.  Returns false on failure, usually because the 
  14.  *         looper processing the message queue is exiting.  Note that a 
  15.  *         result of true does not mean the message will be processed -- if 
  16.  *         the looper is quit before the delivery time of the message 
  17.  *         occurs then the message will be dropped. 
  18.  */  
  19. public boolean sendMessageAtTime(Message msg, long uptimeMillis)  
  20. {  
  21.     boolean sent = false;  
  22.     MessageQueue queue = mQueue;  
  23.     if (queue != null) {  
  24.         msg.target = this;  
  25.         sent = queue.enqueueMessage(msg, uptimeMillis);  
  26.     }  
  27.     else {  
  28.         RuntimeException e = new RuntimeException(  
  29.             this + " sendMessageAtTime() called with no mQueue");  
  30.         Log.w("Looper", e.getMessage(), e);  
  31.     }  
  32.     return sent;  
  33. }  

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

Looper从消息队列中抽取消息

[java] view plaincopyprint?
  1. /** 
  2.  *  Run the message queue in this thread. Be sure to call 
  3.  * {@link #quit()} to end the loop. 
  4.  */  
  5. public static final void loop() {  
  6.     Looper me = myLooper();  
  7.     MessageQueue queue = me.mQueue;  
  8.     while (true) {  
  9.         Message msg = queue.next(); // might block  
  10.         //if (!me.mRun) {  
  11.         //    break;  
  12.         //}  
  13.         if (msg != null) {  
  14.             if (msg.target == null) {  
  15.                 // No target is a magic identifier for the quit message.  
  16.                 return;  
  17.             }  
  18.             if (me.mLogging!= null) me.mLogging.println(  
  19.                     ">>>>> Dispatching to " + msg.target + " "  
  20.                     + msg.callback + ": " + msg.what  
  21.                     );  
  22.             msg.target.dispatchMessage(msg);  
  23.             if (me.mLogging!= null) me.mLogging.println(  
  24.                     "<<<<< Finished to    " + msg.target + " "  
  25.                     + msg.callback);  
  26.             msg.recycle();  
  27.         }  
  28.     }  
  29. }  

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

处理

[java] view plaincopyprint?
  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将不能接收处理消息。在这种情况下,通用的作法是:

[java] view plaincopyprint?
  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在哪个线程里创建的。

如何更新UI才能不出异常呢?SDK告诉我们,有以下4种方式可以从其它线程访问UI线程:
·Activity.runOnUiThread(Runnable)
·View.post(Runnable)
·View.postDelayed(Runnable, long)
·Handler
其中,重点说一下的是View.post(Runnable)方法。在post(Runnable action)方法里,View获得当前线程(即UI线程)的Handler,然后将action对象post到Handler里。在Handler里,它将传递过来的action对象包装成一个Message(Message的callback为action),然后将其投入UI线程的消息循环中。在Handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnable的run方法。而此时,已经路由到UI线程里,因此,我们可以毫无顾虑的来更新UI。

总之:

·Handler的处理过程运行在创建Handler的线程里
·一个Looper对应一个MessageQueue
·一个线程对应一个Looper
·一个Looper可以对应多个Handler
·不确定当前线程时,更新UI时尽量调用post方法


关系


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()结束该循环,实例代码如下:

  class LooperThread extends Thread {      public Handler mHandler;            public void run() {          Looper.prepare();                    mHandler = new Handler() {              public void handleMessage(Message msg) {                  // process incoming messages here              }          };                    Looper.loop();      }  }
   幸好android为我们提供了一个直接生成带有looper线程的方法,及实例化一个HandlerThread对象,通过HandlerThread.getLooper()方法即可获得该HandlerThread的looper对象。
     5,Handler和Thread HandlerThread Looper Message MessageQueue的关系
       Handler类是用来发送和处理消息/Runnable的类,一个Handler类与唯一的一个线程关联,并且该线程是生成该Handler的线程,
它把消息发送到该生成它的线程里的MessageQueue里,然后当Message出队列的时候,就执行该消息。
 post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long),是用来处理runnable对象的;
 sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long), and sendMessageDelayed(Message, long)方法是
用来处理Message对象,一般是立即执行的,但是我们是可以设置时延,还可以循环执行。
可以通过handleMessage (Message msg) 方法来接收消息。
实例化:Handler(Looper looper) 


多线程与异步

Main Thread & UI Thread

当程序启动的时候Android会自动创建一个进程和一个线程,这个线程负责界面更新,收集系统事件和用户的操作事件等并分配给对应的组件,所以这个线程非常重要 被称为主线程,因为所的和UI有关的操作都是在这个线程当中进行的所以也被称作UI线程。所以说默认情况下主线程和UI线程指的是同一个线程。For instance, when the user touches a button on the screen, your app's UI thread dispatches the touch event to the widget, which in turn sets its pressed state and posts an invalidate request to the event queue. The UI thread dequeues the request and notifies the widget that it should redraw itself.

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去执行。

通过一个小例子+源码追踪下它们之间是怎么工作的,关系是什么样的

public class HandleMessageTrackActivity extends Activity {    final static int SHOW_ALERT = 1025;    Activity mActivity;    TextView displayText;    Handler mHandler = new Handler(){        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            switch(msg.what){            case SHOW_ALERT:                showAlert((String)msg.obj);                break;            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        mActivity = this;        displayText = new TextView(this);        setContentView(displayText);        displayText.setText("Just ignore me");                new Thread(){            @Override            public void run(){                String Greetings = "Greetings from another Thread";                mHandler.obtainMessage(SHOW_ALERT, Greetings).sendToTarget();            }        }.start();    }        private void showAlert(String content){        AlertDialog.Builder builder = new Builder(mActivity);        builder.setMessage(content);        builder.create().show();    }}

首先看一下mHandler.obtainMessage(SHOW_ALERT, Greetings).sendToTarget();会执行什么。 通过查看Handler的源码发现执行了下边的代码。

view sourceprint?
public final Message obtainMessage(int what, Object obj){
    return Message.obtain(this, what, obj);
}

接着查看Message中的代码,

 

public static Message obtain(Handler h, int what, Object obj) {    Message m = obtain();    m.target = h;    m.what = what;    m.obj = obj;    return m;}/*** Return a new Message instance from the global pool. Allows us to* avoid allocating new objects in many cases.*/public static Message obtain() {    synchronized (mPoolSync) {        if (mPool != null) {            Message m = mPool;            mPool = m.next;            m.next = null;            return m;        }    }    return new Message();}

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

 

public void sendToTarget() {    target.sendMessage(this);//targe就是一个Handler}sendMessage()会调用下面的sendMessageAtTime()把Message加入MessagQueue;public boolean sendMessageAtTime(Message msg, long uptimeMillis){    boolean sent = false;    MessageQueue queue = mQueue;    if (queue != null) {        msg.target = this;        sent = queue.enqueueMessage(msg, uptimeMillis);    }else {        RuntimeException e = new RuntimeException(                this + " sendMessageAtTime() called with no mQueue");        Log.w("Looper", e.getMessage(), e);    }    return sent;}

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

 

public static final void loop() {    Looper me = myLooper();    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;        }         if (me.mLogging!= null) me.mLogging.println(            ">>>>> Dispatching to " + msg.target + " "                 + msg.callback + ": " + msg.what        );        msg.target.dispatchMessage(msg);//target of a msg is a Handler        if (me.mLogging!= null) me.mLogging.println(             " Finished to    " + msg.target + " "            + msg.callback);//msg.callback is a Runnable            msg.recycle();        }    }}

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

 

/*** Handle system messages here.*/public void dispatchMessage(Message msg) {    if (msg.callback != null) {        handleCallback(msg);// call the run method of the runnable object I guess    } else {        if (mCallback != null) {            if (mCallback.handleMessage(msg)) {            return;            }        }        handleMessage(msg);    }}

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

private final void handleCallback(Message message) {    message.callback.run();}
这就是为什么在Handler中post的Runnable不会开启一个新的线程的原因。经过上面的追踪我们应该能明白不是所有 的线程都可以有Handler去执行handlerMessage或者处理Runnalbe的。其必要条件就是这个线程要有一个一直循环的Looper.Looper一直循环肯定要有一个方法可以退出循环。
public void quit() {    Message msg = Message.obtain();    // NOTE: By enqueueing directly into the message queue, the    // message is left with a null target.  This is how we know it is    // a quit message.    mQueue.enqueueMessage(msg, 0);}

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..


Handler与Looper线程模型


 Android中消息系统模型和Handler Looper

  作为Android中大量使用的Handler,结合Thread使其具有众多的使用形式和方法,

让我一时感觉这个东西有些玄乎,不明所以然,这到底是一个什么样的存在呢?通过网上

资料和源码的学习,这个Handler也差不多弄清楚了,现在总结下这个学习结果。

 

一 Handler作用和概念

通过官方文档了解到Handler的大致概念是:

  Handler能够让你发送和处理消息,以及Runnable对象;每个Handler对象对应一个Thread和

Thread的消息队列。当你创建一个Handler时,它就和Thread的消息队列绑定在一起,然后就可以

传递消息和runnable对象到消息队列中,执行消息后就从消息队列中退出。

 

  Handler的作用就是:调度消息和runnable对象去被执行;使动作在不同的线程中被执行。

  当一个应用程序中进程被创建时,它的主线程专门运行消息队列(messageQueue),去管

理顶层的应用程序相关的对象如:activity,broadcastReceiver,windows等,你可以创建你

的Thread,和主线程进行交互——通过Handler,交互的方法就是通过post或者sendMessage。

但是在你的新线程中,给定的Message或者Runnable,会在适当的时候的被调度和处理。

(即不会被立即处理——阻塞式)。

  这是官方文档中对Handler描述的大致意思(英文比较烂翻译不定正确)。

 

从这些文档中我们大概了解到handler干了些什么:

  •   运行在某个线程上,共享线程的消息队列;
  •   接收消息、调度消息,派发消息和处理消息;
  •   实现消息的异步处理;

基本上就是和消息有关,那么这实际上是在干什么呢?

  ——建立消息处理模型/系统。

  

  要学习Handler,看到肯定是和消息有关,可能还是需要先熟悉一下消息系统的构成和简单原理。

下面就先学习一下消息系统的基本原理。

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

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

    l  消息原型

    l  消息队列

    l  发送消息

    l  消息循环

    l  消息获取

    l  消息派发

    l  消息处理

大致模型图如下:

 

    

 

 

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

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

  从前面文档的分析中我们知道Handler就是用来建立消息处理的系统模型,那么和这里基本消息

系统模型相比,那么Handler又是如何囊括这七个部分的呢?

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

    Handler,Message,MessageQueue,Looper;

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

  

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

 

三 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实现流程分析

  我们知道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一个独立的类,又不属于某个Thread,而这里创建Looper的函数又是静态的,

属于整个Looper类;创建Looper之后交给静态成员变量sThreadLocal保存,获取

sThreadLocal.get(),那么一个静态变量属于整个类,属性更改始终有效。一次创建之后

sThreadLocal.get()永远都不等于null!

  

  而Thread和Looper是唯一对应的,那这里岂不是所有的Thread都是用同一个Looper,不可能!

所以肯定这个ThreadLocal是有玄机的。网上一查:

  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对象;

       

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

复制代码
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完成,存在一个消息调度死循环:    

复制代码
  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进行线程之间有消息传递。感觉这个利用的很好很巧妙。

原文地址:http://www.cnblogs.com/bastard/archive/2012/06/08/2541944.html




0 0