• Android的消息机制: Message/MessageQueue/Handler/Looper


    概览
     
    * 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
     
  • 相关阅读:
    FastJson---高性能JSON开发包
    mybatis中大于等于小于等于的写法
    MarkDown 使用说明示例
    Get和Post的参数传值
    规则引擎 资料收集
    ORA-01033错误解决方案
    mybatis 参数为String,用_parameter 取值
    php中实现记住密码下次自动登录的例子
    php 应用 bootstrap-fileinput 上传文件 插件 操作的方法
    AJAX 跨域请求
  • 原文地址:https://www.cnblogs.com/caca/p/android_looper_message.html
Copyright © 2020-2023  润新知