美文网首页
Handler机制的结构

Handler机制的结构

作者: 吕注意 | 来源:发表于2020-11-20 22:39 被阅读0次

Handler消息机制由四部分组成:

  • Looper:
  • MessageQueue:
  • Handler:
  • Message

Looper、MessageQueue、Handler、Message 之间的关系
从设计模式角度来看,Handler机制可以说是一个生产者-消费者模式:
Handler 是生产者,生产 Message,并将 Message放入 MessageQueue队列中。而 Looper 是消费者,它从 MessageQueue队列中拿到Message进行处理(消费)。

结构图.png

Handler消息机制的实现

  • Message类:消息的封装

    成员变量 说明
    target 调用enqueueMessage()方法的Handler对象实例
    next MessageQueue中下一个Message对象
    when 处理时期,在MessageQueue中Message对象按升序排列
    ...
    • Message的复用:

      因为Android中消息是通过Handler机制驱动的,很多消息都需要用到Handler机制。如果每次消费完一个Message就将对象设置为null,让出内存,在生产Message时又得使用new去重新申请内存,可能会造成内存抖动问题。所以在消费完Message后,不会让出Message内存,而是将其内容置空,留下一个Message壳,在生产下一个Message时可以直接复用该Message。

      1. Message.recycleUnchecked()方法中,会将Message对象的所有配置都重置,只留下一个Message空壳。

        //消费完Message后,重置内容。
        void recycleUnchecked() {
         // Mark the message as in use while it remains in the recycled object pool.
         // Clear out all other details.
           flags = FLAG_IN_USE;
           what = 0;
           arg1 = 0;
           arg2 = 0;
           obj = null;
           replyTo = null;
           sendingUid = UID_NONE;
           workSourceUid = UID_NONE;
           when = 0;
           target = null;
           callback = null;
           data = null;
        ​
           synchronized (sPoolSync) {
             if (sPoolSize < MAX_POOL_SIZE) {
               next = sPool;
               sPool = this;
               sPoolSize++;
             }
           }
        }
        
        
      2. 在重置完Message对象后,使用obtain()方法可以拿到被重置完的Message对象,并进行复用

        public static Message obtain() {
           synchronized (sPoolSync) {
             if (sPool != null) {
               Message m = sPool;
               sPool = m.next;
               m.next = null;
               m.flags = 0; // clear in-use flag
               sPoolSize--;
               return m;
             }
         }
         return new Message();
        }
        ​
        ​
        //Activity中
        new Handler().sendMessage(Message.obtain());
        
        
  • MessageQueue类:传送带,负责存放Message消息,存放消息方法是enqueueMessage()

    成员变量 说明
    mQuitAllowed:boolean 如果消息队列可以退出,则为真。主线程中为fasle
    mMessages:Message 列表中第一个Message消息。后面message由next获得
    mQuitting:boolean 是否正在退出标记位
    ...

    enqueueMessage()中主要就是将要加入的message根据时间升序加入链表中,然后在需要的时候调用nativeWake()去唤醒Looper。插入链表是按照when升序进行排序的。

     //MessageQueue.java
    boolean enqueueMessage(Message msg, long when) {
    //省略
    
      synchronized (this) {
        //如果MessageQueue正在退出
          if (mQuitting) {
              IllegalStateException e = new IllegalStateException(msg.target + " sending message to a Handler on a dead thread");
              Log.w(TAG, e.getMessage(), e);
              msg.recycle();
              return false;
          }// end 如果MessageQueue正在退出
    
          msg.markInUse();
          msg.when = when;
          //MessageQueue中保存着第一个Message,即mMessages
          Message p = mMessages;
          //是否需要唤醒标记位
          boolean needWake;
          //按照时间排序,与msg对比,when小的排前面
          if (p == null || when == 0 || when < p.when) {
              msg.next = p;
              mMessages = msg;
              needWake = mBlocked;
          } else {
              needWake = mBlocked && p.target == null && msg.isAsynchronous();
              Message prev;
              for (;;) {
                  prev = p;
                  p = p.next;
                  if (p == null || when < p.when) {
                      break;
                  }
                  if (needWake && p.isAsynchronous()) {
                      needWake = false;
                  }
              }
              msg.next = p; // invariant: p == prev.next
              prev.next = msg;
          }
    
          if (needWake) {
              nativeWake(mPtr);
          }
        }
        return true;
    }
    
  • Handler类:生产(发送)消息的源头

    在Handler类中,无论我们调用sendMessage()、postMessage()还是其他的方法,最终都会调用到enqueueMessage()方法上。

    enqueueMessage()方法最终走到了MessageQueue.enqueueMessage()

    Handler handler = new Handler();
    handler.sendMessage(Message.obtain());
    
    
    //Handler.java 
    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,long uptimeMillis) {
    msg.target = this;
    msg.workSourceUid = ThreadLocalWorkSource.getUid();
    
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
    }
    
  • Looper类:处理消息,主要通过loop()方法中的死循环获取MessageQueue中的Message

    主线程的Looper在应用启动时便启动且开始了死循环,它是在ActivityThread.main()方法中初始化并启动的。Looper的初始化调用的是Looper.prepareMainLooper()

    //ActivityThread.java
    public static void main(String[] args) {
        //省略
    
        Looper.prepareMainLooper();//<<<<看这里
    
        //省略
    
    }
    
    1. Looper.prepareMainLooper()方法中,调用preapre(false)对Looper进行初始化。其中参数false最终会被设置到MessageQueue中的成员变量mQuitAllowed中,表示该线程对应的MessageQueue不能调用quit()方法。

      //Looper.java
      public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
        sMainLooper = myLooper();
        }
      }
      
      
      void quit(boolean safe) {
        //如果 mQuitAllowed == fasle ,即不允许退出。则调用该方法会抛出异常
        if (!mQuitAllowed) {
          throw new IllegalStateException("Main thread not allowed to quit.");
        }
      
        //省略
      }
      
    2. prepare()中,会去判断当前线程是否已经存在一个Looper对象实例,如果没有则通过new Looper()新建一个Looper对象实例并保存到sThreadLocal中。如果该线程原本就有了一个Looper对象实例,则抛出异常。因此一个线程只能有一个Looper对象实例

      //Looper.java
      private static void prepare(boolean quitAllowed) {
          if (sThreadLocal.get() != null) {
              throw new RuntimeException("Only one Looper may be created per thread");
          }
          sThreadLocal.set(new Looper(quitAllowed));
      }
      

      如何保证每个线程中Looper的唯一?

      答:通过在prepare()方法中对当前线程Looper对象实例是否唯一进行检测,且新建好的Looper会存储在静态常量sThreadLocal中,两部分来保证线程中Looper实例的唯一。

    3. new Looper()中,会一并初始化MessageQueue对象实例。也就是说每个Looper会持有一个MessageQueue对象,且因为Looper在线程中的唯一性,MessageQueue在线程中也是唯一的。

      private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
      }
      
    4. 初始化完Looper后,调用loop()方法进行死循环获取MessageQueue中的message进行操作

      //ActivityThread.java
      public static void main(String[] args) {
      //省略
      
          Looper.prepareMainLooper();
      
      //省略
      
          ActivityThread thread = new ActivityThread();
          thread.attach(false, startSeq);
      
          if (sMainThreadHandler == null) {
              sMainThreadHandler = thread.getHandler();
          }
      
      //省略
      
          Looper.loop();//<<<<<<<<<<<<<<<<<看这里
      
          throw new RuntimeException("Main thread loop unexpectedly exited");
      }
      
    5. loop()

      1. 拿到当前线程中的MessageQueue,并且调用了MessageQueue.next(),在next()中继续用死循环获取Message,如果下一个Message处理的时机还没到,会进行阻塞休眠。

        Message next() {
        
          //mPtr 类似线程的id的东西,在休眠和唤醒时有用。在native层初始化
          final long ptr = mPtr;
          if (ptr == 0) {
              return null;
          }
        
          int pendingIdleHandlerCount = -1; // -1 only during first iteration
          int nextPollTimeoutMillis = 0;
          for (;;) {
              if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
          }
        
        //使用native的方法休眠,时长 == nextPollTimeoutMillis
            nativePollOnce(ptr, nextPollTimeoutMillis);
        
          synchronized (this) {
              final long now = SystemClock.uptimeMillis();
              Message prevMsg = null;
              Message msg = mMessages;
           
              //省略
            
            if (msg != null) {
                //通过when判断下一个Message到时间处理没
                if (now < msg.when) {
                //下一个Message还没有准备好。设置一个超时以在它准备好时唤醒。
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                //下一个Message到时间处理了
                    mBlocked = false;
                    if (prevMsg != null) {//这个跟异步Message有关
                        prevMsg.next = msg.next;
                    } else {//一般的同步Message
                        //将第二个Message设置给mMessages,
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;//<<<<<<<<<< 正常情况下返回
                }
            } else {
                // 没有消息,设置 -1 ,将无限期休眠。
                //在下一个循环中调用 nativePollOnce()时休眠
                nextPollTimeoutMillis = -1;
            }
            
            //调用quit()时,mQuitting==true。
            //主线程不能调用
            if (mQuitting) {
                dispose();
                return null;//<<<<<<<<<<< 子线程调用quit()后,会返回null
            }
        
            //省略
          }
         }
        
      2. 拿到要处理的Message后,判空,如果为空,则退出Loop循环。非空则调用handler中的dispatchMessage()方法进行分发,实现线程间通信。

         public static void loop() {
          final Looper me = myLooper();
        
          final MessageQueue queue = me.mQueue;
        
          //省略
        
          for (;;) {
              Message msg = queue.next(); // might block
        
              //判空,结束loop死循环
              if (msg == null) {
                  return;
              }
        
        
              //省略
        
              try {
                  //msg.target == handler
                  msg.target.dispatchMessage(msg);
                  if (observer != null) {
                      observer.messageDispatched(token, msg);
                  }
                  dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
              } catch (Exception exception) {
                  if (observer != null) {
                      observer.dispatchingThrewException(token, msg, exception);
                  }
                  throw exception;
              } finally {
                  ThreadLocalWorkSource.restore(origWorkSource);
                  if (traceTag != 0) {
                      Trace.traceEnd(traceTag);
                }
           }
        
        
            //省略
        
            //Message清空数据。复用机制
            msg.recycleUnchecked();
          }
        }
        

相关文章

  • Handler机制的结构

    Handler消息机制由四部分组成: Looper: MessageQueue: Handler: Message...

  • Handler机制小结

    Handler笔记 什么是handler机制?handler机制的主要成员1、handler:负责发送处理消息2、...

  • 深入理解Handler机制之引路篇

    要想深入理解Handler机制,就要理解: Android为何要引入Handler机制? Handler机制究竟是...

  • Android 的消息机制

    Android 消息机制主要是指 Handler 的运行机制。 **Handler **Handler 的运行需要...

  • Android:Handler 机制和原理?

    一、Handler机制概述 Handler机制也可以说是消息机制,Handler的运行时需要MessageQueu...

  • 消息机制

    消息机制Handler的工作原理 Android中的消息机制主要就是指Handler的运行机制,而Handler的...

  • Android消息机制

    Handler Android消息机制主要指的是Handler运行机制,Handler底层需要MessageQue...

  • Android Handler机制详解

    Android Handler机制1--ThreadLocalAndroid Handler机制2--Looper...

  • Android的消息机制

    Handler Android消息机制主要是Handler的运行机制,Handler的运行需要底层的Message...

  • android handler 机制 很简单

    1.android handler机制 handler机制,也就是android的异步消息处理机制。但是这个机制不...

网友评论

      本文标题:Handler机制的结构

      本文链接:https://www.haomeiwen.com/subject/cswjiktx.html