概览
 
* Message:消息。消息里面可包含简单数据、Object和Bundle,还可以包含一个Runnable(实际上可看做回调)。
* MessageQueue:消息队列,供Looper线程消费消息。
* Looper:用于循环处理Message,一个Thread结合一个Looper来实现消息循环处理。Android App的主线程包含了Looper。
* Handler:负责向当前Looper线程发送Message,并实现如何处理消息的回调,回调可放到Callback接口的实现中,也可以放在传递进去的Runnable中的run中。
 
 
消息处理流程
 
1. MainThread(一个Looper Thread)正在运行,线程中有MessageQueue可交互,并循环处理MessageQueue中的Message。
2. 在MainThread中创建一个Handler,handler与当前线程Looper的MessageQueue绑定。
3. 通过handler.sendMessage(Message msg)向MessageQueue发送消息,等候执行;通过handler.post(Runnable r)向MessageQueue发送一个空消息,该空消息附加了Runnable,等候执行。
4. MainThread轮询MessageQueue的Message,抛给Message对应的Handler执行。
 

Message
 
* 最好通过Message.obtain()来创建Message对象,从消息池里创建Message更高效。
 
源码分析
public final class Message implements Parcelable
{
     public int what; // 用户定义的标识码
     public int arg1; // 用来存储简单的数据,这样可以不使用Object/Bundle来做消息。
     public int arg2;
     public Object obj; // 对象型数据。
     public Messenger replyTo; 
     Bundle data; // 复杂型消息数据
     // Message的最终处理分两种情况:
     Handler target; // 1)通过Message的target(Handler)处理消息,具体是Handelr实现handleMessage()。
     Runnable callback; // 2)通过空消息的callback(Runnable)处理消息,具体是丢弃Message,然后直接调用run()。
     private static final Object sPoolSync = new Object(); // 消息池用到的锁
     private static Message sPool ; // 从消息池中取出的可用的消息对象。每取一次,这里就放置一个可用的。
     private static int sPoolSize = 0; // 当前可用的消息对象数量
     private static final int MAX_POOL_SIZE = 50 ;  // 池存放最大量
     Message next; // 实现链表式消息池
 
     // 从消息池中取一个可用的消息对象
     public static Message obtain() {
          synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null; 
                sPoolSize--;
                return m;
            }
          }
          return new Message();
     }
 
     // 从现有Message复制并返回
    public static Message obtain(Message orig) {
        Message m = obtain();
        m.what = orig.what;
        m.arg1 = orig.arg1;
        m.arg2 = orig.arg2;
        m.obj = orig.obj;
        m.replyTo = orig.replyTo;
        if (orig.data != null) {
            m.data = new Bundle(orig.data);
        }
        m.target = orig.target;
        m.callback = orig.callback;
 
        return m;
    }
 
     // 发送消息 
     public void sendToTarget() {
          target.sendMessage(this); // 调用的是 handler 的 sendMessage()
     }
 
     // 消息回收
     public void recycle() {
          clearForRecycle(); // 清除Message对象的所有信息
          synchronized (sPoolSync) {
               if(sPoolSize < MAX_POOL_SIZE){
                    next = sPool; // 下一个可用Message是当前sPool(可用)
                    sPool = this ; // 当前可用的Message为正在释放清除的Message对象
                    sPoolSize++; // 可用对象数量递增
               }
          }
     }
}
 
 
MessageQueue
 
* holding the list of messages to be dispatched by a Looper。
* 不能直接向Looper的MessageQueue添加Message,需要通过Handler。
* 可通过 Looper.myQueue()获取到当前线程的MessageQueue。
 

Handler
 
* 创建一个Handler就会绑定到当前Thread/MessageQueue,之后,Handler可以向MessageQueue发送Message和Runnable,等候轮询执行。
* 发送一个Message:sendMessage(Message m)。
* 发送一个Runnable:post(Runnable r) 。
 
 
public class Handler
{
     // 自定义的Handler必须实现该方法,用于处理消息
     public void handleMessage(Message msg){}
     // 或者指定一个实现了Callback接口的类
     public interface Callback {
          public boolean handleMessage(Message msg);
     }
 
     // 构造函数
     // 默认情况下,handler会关联到当前Thread的Looper,如果没有Looper,抛异常
     public Handler(Looper looper,Callback callback/*相当于指定了handleMessage()函数*/,boolean async){ 
          mLooper=looper; mQueue=looper.mQueue; mCallback =callback;mAsynchronous = async;
     }
 
     public final Message obtainMessage(){ return Message.obtain(this); } // 直接调用的Message的obtain
 
     // ---------------------------------------------------------------
     // 发送消息到MessageQueue
     // handler.sendXXX均调用此方法
     public boolean sendMessageAtTime(Message msg,long uptimeMillis) {
          MessageQueue queue = mQueue;
          return enqueueMessage(queue,msg,uptimeMillis);
     }
     private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {msg.setAsynchronous(true);}
        return queue.enqueueMessage(msg, uptimeMillis);
     }
 
     // ---------------------------------------------------------------
     // 发送Runnable到MessageQueue
     // 原理是把Runnable附加到一个空消息的callback上,当执行消息时,如果发现有callback,则执行callback。
     public final boolean post(Runnable r) {
          return sendMessageDelayed(getPostMessage(r),0);
     }
 
     private static getPostMessage(Runnable r,Object token) {
          Message m = Message.obtain();
          m.obj = token;
          m.callback = r; // 指定Message的callback为r。通过sendMessage的消息没有callback,包含callback的Message将会被其callback执行。
          return m;
     }
 
     // ---------------------------------------------------------------
     // 处理消息
     // 消息在Looper中是通过调用这个函数来实现处理消息的
     public void dispatchMessage(Message msg) {
          if(msg.callback!=null){ handleCallback(msg); } // 在Runnable中处理
          else {
               handleMessage(msg); // 调用Handler处理消息的函数
          }
     }
     private static void handleCallback(Message message) { 
          message.callback.run(); //消息被丢弃,并且直接调用run(),而不是新开线程。
      }
 
 
}// end handler()
 

Looper
 
* 默认线程并没有包含可以循环处理消息的功能,Looper类可以帮助线程实现消息循环。
 
public final class Looper
{
     static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); // 线程本地变量,每个线程一个Looper。
 
     final Message mQueue;
     final Thread mThread;
 
     private Looper(boolean quitAllowed){
          mQueue = new MessageQueue(quitAllowed);
          mThread = Thread.currentThread();
     }
 
     // --------------------------------------------------------------------
     // 准备。为当前线程创建一个Looper对象
     static void prepare(boolean quitAllowed/*MessageQueue是否可退出*/) {
          if(sThreadLocal.get()!=null){/*Exception,当前线程的Looper已存在,一个线程一个Looper*/}
          sThreadLocal.set(new Looper(quitAllowed));
     }
 
     // --------------------------------------------------------------------
     // 开始循环
     public static void loop() {
          final Looper me = myLooper();// 当前线程的Looper实例
          final MessageQueue queue = me.mQueue;
          for(;;){
               Message msg = queue.next();
               if(msg == null) { return;}
 
               msg.target.dispatchMessage(msg); // 由Handler处理该消息
 
               msg.recycle(); // 清理该消息,清空后返回消息池。
 
          }//end for
     }// end loop()
 
     // --------------------------------------------------------------------
     public void quit() { mQueue.quit(false); }
     public boolean isIdling(){ return mQueue.isIdling();}
 
} // class end.
 
 
 

Demo
 

Demo#1 发送消息
class SomeActivity
{
  @Override
  public void onCreate(...){
  testMessage();
}

void testMessage(){
  MyHandler handler = new MyHandler();
  // or
  handler = new Handler(/*this.getMainLooper(),*/ new Handler.Callback(){ /*...*/ });

  // 发送Message
  Message m1 = new Message();
  m.setTarget(h);
  m.sendToTarget();

  // 发送Runnable(内部其实是发送了一个Message+Runnable)
  handler.post(new Runnable(){
    @Override
    public void run(){
      // 在主线程中运行
    }
  });
}

class MyHandler extends Handler{
  @Override
  public void handleMessage(Message msg){ /*...*/ }
}

Demo#2 自定义Looper线程
public static void testLooper()
{
  Thread tLooper = new Thread(new Runnable(){

  @Override
  public void run() {
    Looper.prepare();

    MyHandler h = new MyHandler();
    // 发送消息
    h.sendEmptyMessage(0);
    // 发送Runnable
    h.post(new Runnable(){
      @Override
      public void run() {
      Log.i("test","[in post runnable]threadid:"+Thread.currentThread().getId()); // tLooper线程ID
    }});

    Looper.loop(); // 一直循环。即使没有消息
  }});
  tLooper.start();
}

 

references
 

Android的消息机制: Message/MessageQueue/Handler/Looper的更多相关文章

  1. Android 进阶14:源码解读 Android 消息机制( Message MessageQueue Handler Looper)

    不要心急,一点一点的进步才是最靠谱的. 读完本文你将了解: 前言 Message 如何获取一个消息 Messageobtain 消息的回收利用 MessageQueue MessageQueue 的属 ...

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

    http://www.cnblogs.com/bastard/archive/2012/06/08/2541944.html Android中消息系统模型和Handler Looper 作为Andro ...

  3. 深入理解Message, MessageQueue, Handler和Looper

    做过Android的都知道Message, MessageQueue, Handler和Looper,但知道不代表你理解它们.有时觉得用得很顺手,但Android怎么实现又说不上来,总觉得似懂非懂.不 ...

  4. Android 基础 十一 Android的消息机制

    Handler是Android消息机制的上层接口,这使得在开发应用过程中我们只需要和Handler交互即可.Handler的使用过程很简单,通过它可以轻松地将一个任务切换到Handler所在的线程中去 ...

  5. 【原创】源码角度分析Android的消息机制系列(五)——Looper的工作原理

    ι 版权声明:本文为博主原创文章,未经博主允许不得转载. Looper在Android的消息机制中就是用来进行消息循环的.它会不停地循环,去MessageQueue中查看是否有新消息,如果有消息就立刻 ...

  6. 《Android开发艺术探索》读书笔记 (10) 第10章 Android的消息机制

    第10章 Android的消息机制 10.1 Android消息机制概述 (1)Android的消息机制主要是指Handler的运行机制,其底层需要MessageQueue和Looper的支撑.Mes ...

  7. Android的消息机制

    一.简介 ①.我们不能在子线程中去访问UI空控件,这是时候只能通过Handler将更新UI的操作放到主线程中去执行 ②.Handler的组成:messageQueue和Looper的支持 ③.Mess ...

  8. 【原创】源码角度分析Android的消息机制系列(一)——Android消息机制概述

    ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 1.为什么需要Android的消息机制 因为Android系统不允许在子线程中去访问UI,即Android系统不允许在子线程中更新UI. 为什 ...

  9. Android的消息机制简单总结

    参考文章: http://gityuan.com/2015/12/26/handler-message-framework/#next 参考资料: Android Framework的源码: Mess ...

随机推荐

  1. Maven学习之 插件plugin

    Maven本质上是一个执行插件的框架.插件共分两类:build插件和reporting插件. build插件,会在build阶段被执行,应该配置在POM的<build/>元素中. repo ...

  2. STF(SmartPhone Test Farm)Mac版本环境搭建

    它的github页面为: https://github.com/openstf/stf 1.Linux一些基本包的安装: 在控制台分别运行 sudo apt-get update sudo apt-g ...

  3. [PHP] php实现文件下载

    1. 设置超链接的href属性 <a href="文件地址"></a> 如果浏览器不能解析该文件,浏览器会自动下载.而如果文件是图片或者txt,会直接在浏览 ...

  4. java多条件不定条件查询

    网站或各类管理系统都会用到搜索,会用到一个或多个不确定条件搜索,单条件搜索比较简单,有时候会有多个条件共同查询,如果系统中已经提供了相关的方法供你使用最好,像我做这老系统改版,需要添加搜索,就要自己写 ...

  5. IntelliJIDEA 14创建Maven管理的Java Web项目

    1.新建项目,选择Maven,点击Next继续. 接着输入项目名 接着直接点击Finish即可 下图就是创建完毕后的Maven项目,双击pom.xml查看POM文件内容,可以自行添加Maven的依赖. ...

  6. Objective C笔记(第一天)

    • OC语言概述 1.早在20世纪80年代早期,Bard Cox发明了Objective C, 是扩充的C,面向对象的编程语言. 2.NEXTSTEP简称NS a.1985年,Steve Jobs成⽴ ...

  7. Android View 如何绘制

    上文说道了Android如何测量,但是一个漂亮的控件我只知道您长到哪儿,这当然不行.只需要简单重写OnDraw方法,并在Canvas(画布)对象上调用那根五颜六色的画笔就能够画出这控件"性感 ...

  8. 我的Linux随笔目录

    现在整理博客的时间少了,大多是在用为知笔记收藏和整理,一次集中发点Linux相关随笔整理和一个目录,是按时间顺序来的.每一篇都是自己用过之后整理的,应用场景已经尽可能的说明了,不明白的可以Q我,上班时 ...

  9. 使用NHibernate(7)-- 一对一 && 一对多 && 多对多

    1, 一对一. 对于数据量比较大的时候,考虑查询的性能,肯能会把一个对象的属性分到两个表中存放:比如用户和用户资料,经常使用的一般是Id和用户名,用户资料(学校,籍贯等)是不经常被查询的,所以就会分成 ...

  10. 【ASP.NET Web API教程】6.2 ASP.NET Web API中的JSON和XML序列化

    谨以此文感谢关注此系列文章的园友!前段时间本以为此系列文章已没多少人关注,而不打算继续下去了.因为文章贴出来之后,看的人似乎不多,也很少有人对这些文章发表评论,而且几乎无人给予“推荐”.但前几天有人询 ...