Handler總結

  • 我們看下基本的概念
  • messagequeue===中文的翻譯是消息隊列,它的內部存儲了一組消息,以隊列的形式對外提供增加和刪除的方法,但是他的內部不是隊列的結構形式,而是采用單鏈表的數據結構來存儲消息列表
  • looper==輪詢器,也可以理解為消息循環,由于messagequeue是一個消息容器,所以他負責不斷的去輪訓消息,如果有消息處理的話就去處理消息,否則就一直等待著。他還有一個特殊的概念threadlocal
    ,并不是線程,他的作用是在每個線程中存儲數據,負責綁定當前的線程的loop
  • 首先我們知道創建一個handel

    new Handler();就行了但是其中內部干了什么呢?

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

                }

            //獲取loper對象,如果lopper對象為空就會報異常,這就是為什么我們在子線程使用需要主動的調用 Looper.prepare();

            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;

        }

        

       我們看下Looper.prepare();的源碼可以得知,只有sThreadLocal為空的時候起創建了一個Looper對象

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

    }

    

    那么為什么我們在主線程就沒有調用就沒事呢!

    其實你在創建activitythred的內部就給你調用了Looper.prepareMainLooper()調用了Looper.prepare()方法,因此我們應用程序的主線程中會始終存在一個Looper對象,從而不需要再手動去調用Looper.prepare()方法了。

  • 然后我們發送消息需要什么?

      messag對message,我們看看怎么創建一個message,那么創建message有那些方式,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();
    

    }`

  • 有了消息我們就要發送出去,如何發送呢!
    `handler.sendMessage(message);`,這樣我們就可以把消息發送出去。那么它里面是如何發送消息的,我們通過看源碼得知他最終回調用sendMessageAtTime(),我們看下源碼

    //其中msg參數就是我們發送的Message對象,而uptimeMillis參數則表示發送消息的時間,它的值等于自系統開機到當前時間的毫秒數再加上延遲時間

     public boolean sendMessageAtTime(Message msg, long uptimeMillis) {

        //如果quer為空就會停止輪訓消息

        MessageQueue queue = mQueue;

        if (queue == null) {

            RuntimeException e = new RuntimeException(

                    this + " sendMessageAtTime() called with no mQueue");

            Log.w("Looper", e.getMessage(), e);

            return false;

        }

        //進入enqueueMessage

        return enqueueMessage(queue, msg, uptimeMillis);

    }

    //通過看源碼我們知道,MessageQueue是在調用looper的時候創建的,因此一個Looper也就對應了一個MessageQueue。

    private Looper(boolean quitAllowed) {

        mQueue = new MessageQueue(quitAllowed);

        mThread = Thread.currentThread();

    }

    

    

    

    

    

    我們看下enqueueMessage的方法,在這里進行消息的入隊,將消息插入到messagequene

        final boolean enqueueMessage(Message msg, long when) {

        if (msg.when != 0) {

            throw new AndroidRuntimeException(msg + " This message is already in use.");

        }

        //如果為空將報異常,msg.target就是handel

        if (msg.target == null && !mQuitAllowed) {

            throw new RuntimeException("Main thread not allowed to quit");

        }

        synchronized (this) {

            //如果調用了quit就會賦值為true

            if (mQuiting) {

                RuntimeException e = new RuntimeException(msg.target + " sending message to a Handler on a dead thread");

                Log.w("MessageQueue", e.getMessage(), e);

                return false;

            } else if (msg.target == null) {

                mQuiting = true;

            }

            msg.when = when;

            Message p = mMessages;

            //在這里他們將按照時間的順序排列

            if (p == null || when == 0 || when < p.when) {

                msg.next = p;

                mMessages = msg;

                this.notify();

            } else {

                Message prev = null;

                while (p != null && p.when <= when) {

                    prev = p;

                    p = p.next;

                }

                msg.next = prev.next;

                prev.next = msg;

                this.notify();

            }

        }

           if (needWake) {

                //在native層進行消息的傳遞

                nativeWake(mPtr);

            }

        return true;

    }

  • 接下來我們看下消息的輪訓 loop.loop()

    public static final void loop() {

    //獲取Looper

    Looper me = myLooper();

    MessageQueue queue = me.mQueue;

    while (true) {

        //這里面也是個死循環去取消息如果當前MessageQueue中存在mMessages(即待處理消息),就將這個消息出隊,然后讓下一條消息成為mMessages,否則就進入一個阻塞狀態,一直等到有新的消息入隊。
      //MessageQueue中的nex方法,去輪訓消息內部是一個無限的循環輪詢,這里面要想退出這個無限的循環只有queue.next()
      返回null,而要讓他返回null,通過看源碼mQuitting就行了,也就是說只要調用quit就可以了
        Message msg = queue.next(); // might block

        if (msg != null) {

        //如果handel為空將直接退出循環

            if (msg.target == null) {

                return;

            }

            if (me.mLogging!= null) me.mLogging.println(

                    ">>>>> Dispatching to " + msg.target + " "

                    + msg.callback + ": " + msg.what

                    );

            //這里就會調用handeld的dispatchMessage進行消息的分發,為什么是msg.target是handel通過源碼我們看到enqueueMessage里面進行的賦值 msg.target = this;我們看下怎么分發的

            msg.target.dispatchMessage(msg);

            if (me.mLogging!= null) me.mLogging.println(

                    "<<<<< Finished to    " + msg.target + " "

                    + msg.callback);

            msg.recycle();

        }

    }

}





//我們進入到這個方法

public void dispatchMessage(Message msg) {

    if (msg.callback != null) {
       //這個方法熟悉把就把消息傳遞到我們重寫的主線程的方法了,在這里進行回調handleMessage
        handleCallback(msg);

    } else {

        if (mCallback != null) {

            if (mCallback.handleMessage(msg)) {

                return;

            }

        }



        handleMessage(msg);

    }

}



最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容