Handler消息機(jī)制解析

Handler消息機(jī)制解析

Android提供用來更新UI的一套機(jī)制,也是一套消息處理機(jī)制,可以發(fā)送消息和處理消息。

Handler

Handler對(duì)象來與Looper溝通,以便push新消息到MessageQueue里;或者接收Looper從Message Queue取出)所送來的消息。

方法

  1. 構(gòu)造方法

     public Handler(Callback callback, boolean async) {
         if (FIND_POTENTIAL_LEAKS) {
             final Class<? extends Handler> klass = getClass();
             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                 (klass.getModifiers() & Modifier.STATIC) == 0) {
             Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                 klass.getCanonicalName());
             }
         }
    
         mLooper = Looper.myLooper();
         if (mLooper == null) {
             throw new RuntimeException(
             "Can't create handler inside thread that has not called Looper.prepare()");
         }
         mQueue = mLooper.mQueue;
         mCallback = callback;
         mAsynchronous = async;
     }
    

幾個(gè)構(gòu)造方法最終都會(huì)調(diào)用這個(gè)構(gòu)造方法,myLooper()。獲取當(dāng)前Looper對(duì)象,通過looper獲取MessageQueue,完成了handler和looper的關(guān)聯(lián)

  1. 消息發(fā)送方法

     public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
         MessageQueue queue = mQueue;
         if (queue == null) {
             RuntimeException e = new RuntimeException(
                 this + " sendMessageAtTime() called with no mQueue");
             Log.w("Looper", e.getMessage(), e);
             return false;
         }
         return enqueueMessage(queue, msg, uptimeMillis);
     }
    

如果隊(duì)列為null就拋異常,否則向隊(duì)列中放入消息。

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

放入消息的時(shí)候要指定目標(biāo),默認(rèn)是發(fā)送個(gè)自己。

消息放入隊(duì)列后,Looper通過looper()處理消息隊(duì)列

  1. 分發(fā)消息方法

      /**
      * Handle system messages here.
      */
     public void dispatchMessage(Message msg) {
         if (msg.callback != null) {
             handleCallback(msg);
         } else {
             if (mCallback != null) {
                 if (mCallback.handleMessage(msg)) {
                     return;
                 }
             }
             handleMessage(msg);
         }
     }
    

在這個(gè)方法內(nèi)調(diào)用handleCallback方法處理消息

內(nèi)部接口Callback

public interface Callback {
    public boolean handleMessage(Message msg);
}

Looper

一個(gè)線程只能產(chǎn)生一個(gè)Looper對(duì)象,由它來管理此線程里的MessageQueue(消息隊(duì)列)。

  1. 內(nèi)部包含了一個(gè)消息隊(duì)列MessageQueue所有handler發(fā)送的消息都通過這個(gè)隊(duì)列。
  2. Looper.Looper方法是一個(gè)死循環(huán),不斷從MessageQueue中取Message,有就處理,沒有就阻塞

Looper類的方法

  1. Looper.prepare()方法(調(diào)用prepare(true))

     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));
     }
    

這個(gè)方法創(chuàng)建新的Looper,如果一個(gè)線程中已經(jīng)有一個(gè)Looper就會(huì)報(bào)錯(cuò),如果沒有就調(diào)用私有構(gòu)造方法創(chuàng)建一個(gè)新的Looper

  1. 私有的構(gòu)造方法

         private Looper(boolean quitAllowed) {
             mQueue = new MessageQueue(quitAllowed);
             mThread = Thread.currentThread();
         } 
    

創(chuàng)建了一個(gè)MessageQueue,并關(guān)聯(lián)當(dāng)前Thread

  1. myLopper()

     /**
      * Return the Looper object associated with the current thread.  Returns
      * null if the calling thread is not associated with a Looper.
      */
     public static @Nullable Looper myLooper() {
         return sThreadLocal.get();
     }
    

獲取當(dāng)前Looper對(duì)象,

  1. myQueue()

     /**
      * Return the {@link MessageQueue} object associated with the current
      * thread.  This must be called from a thread running a Looper, or a
      * NullPointerException will be thrown.
      */
     public static @NonNull MessageQueue myQueue() {
         return myLooper().mQueue;
     }
    

獲取Looper中的MessageQueue

  1. 死循環(huán)方法 loop()

     /**
      * Run the message queue in this thread. Be sure to call
      * {@link #quit()} to end the loop.
      */
     public static void loop() {
         final Looper me = myLooper();
         if (me == null) {
             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
         }
         final MessageQueue queue = me.mQueue;
    
         // Make sure the identity of this thread is that of the local process,
         // and keep track of what that identity token actually is.
         Binder.clearCallingIdentity();
         final long ident = Binder.clearCallingIdentity();
    
     for (;;) {
         Message msg = queue.next(); // might block
         if (msg == null) {
             // No message indicates that the message queue is quitting.
             return;
         }
    
         // This must be in a local variable, in case a UI event sets the logger
         Printer logging = me.mLogging;
         if (logging != null) {
             logging.println(">>>>> Dispatching to " + msg.target + " " +
                     msg.callback + ": " + msg.what);
         }
    
         msg.target.dispatchMessage(msg);
    
         if (logging != null) {
             logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
         }
    
         // Make sure that during the course of dispatching the
         // identity of the thread wasn't corrupted.
         final long newIdent = Binder.clearCallingIdentity();
         if (ident != newIdent) {
             Log.wtf(TAG, "Thread identity changed from 0x"
                     + Long.toHexString(ident) + " to 0x"
                     + Long.toHexString(newIdent) + " while dispatching to "
                     + msg.target.getClass().getName() + " "
                     + msg.callback + " what=" + msg.what);
         }
    
         msg.recycleUnchecked();
         }
     }
    

這個(gè)方法用于處理隊(duì)列中的消息:通過myLooper()方法獲取單前的Looper,從而獲取當(dāng)前的消息隊(duì)列,通過消息隊(duì)列的next()方法獲取消息,消息不為null的時(shí)候調(diào)用handler的dispatchMessage(msg)方法

MessageQueue消息隊(duì)列

存儲(chǔ)消息的容器

ThreadLocal class

作用:在線程中保存信息變量。負(fù)責(zé)thread和looper之間的關(guān)系

方法

  1. set

     public void set(T value) {
         Thread currentThread = Thread.currentThread();
         Values values = values(currentThread);
         if (values == null) {
             values = initializeValues(currentThread);
         }
             values.put(this, value);
     }
    

鍵值對(duì)的形式存儲(chǔ)Thread和Looper之間的關(guān)系,Thread是key,Looper是值

  1. get

     public T get() {
         // Optimized for the fast path.
         Thread currentThread = Thread.currentThread();
         Values values = values(currentThread);
         if (values != null) {
             Object[] table = values.table;
             int index = hash & values.mask;
             if (this.reference == table[index]) {
                 return (T) table[index + 1];
             }
         } else {
             values = initializeValues(currentThread);
         }
    
         return (T) values.getAfterMiss(this);
     }
    

取出當(dāng)前線程對(duì)應(yīng)的looper。

內(nèi)部類 Values

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容