兩張圖看透Android Handler使用與機制

1.Handler的使用

  • 如圖所示,需要做的操作有兩步:

    1. 在主線程中實例化一個Handler,并且重寫HandleMessage方法用來處理子線程發送來的消息。

    2. 在子線程中,首先聲明Message對象,并將Message使用主線程中實例化的Handler的sendMessage(Message)方法發送給主線程。

    public class MainActivity extends AppCompatActivity {
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
          final Handler handler=new Handler(){
              @Override
              public void handleMessage(Message m){
                  //更新ui操作
              }
          };
          new Thread(){//子線程開啟
              @Override
              public void run(){
                  Message m=new Message();
                  handler.sendMessage(m);
              }
          };
      }
    }

2.Handler的機制

  • 在使用sendMessage和handleMessage之前是有很多已經隱藏的封裝好的過程的,現在一一講解。

2.1 被消息傳遞的線程A準備

  • 首先要在被消息傳遞的線程中創建Looper,因為Handler創建的時候要綁定當前線程的Looper,使用Looper.prepare()建立。

    • Looper.prepare()
      public static void prepare() {
      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));
      }
      private Looper(boolean quitAllowed) {
          mQueue = new MessageQueue(quitAllowed);
          mThread = Thread.currentThread();
      }

      總的來說,prepare干了兩件事: 創建MessageQueue和綁定當前線程。

    </li>
  • 然后使用Looper.loop()讓Looper開始循環訪問MessageQueue。

    • Looper.loop();

      public static void loop() {
        // 拿到與當前線程關聯的looper對象
          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;
          .......................................

      for (;;) {
          Message msg = queue.next(); // might block
          ...................................
          msg.target.dispatchMessage(msg);
          ..........................................
          msg.recycleUnchecked();// 回收Message對象
      }
      

      }</code></pre>

      總的來說,loop干了三件事:

      1.拿到當前線程的looper。

      2.根據looper拿到MessageQueue。

      3.使用for循環對MessageQueu進行無限循環詢問。

      在for循環中也主要干了三件事:

      1.從消息隊列中取消息,如果沒有就阻塞。

      2.調用msg.target.dispatchMessage(msg)方法對Message進行處理。

      3.處理完成后調用msg.recycleUnchecked()回收資源。

      </li> </ul> </li>
    • 創建Handler,作為線程間通信的工具。

      public Handler(Looper looper, Callback callback, boolean async){
            mLooper = looper;
            // 與這個Handler關聯的Looper中的消息隊列
            mQueue = looper.mQueue;
            ...............
      }

      創建Handler時將當前線程的Looper和Looper中的MessageQueue取到。

    • </ul>

      2.2 傳遞消息的線程B準備

      • 創建Message時,使用Message.obtain()的效果大于New Message(),因為享元模式,維護了一個大小為50的Message對象池,比重復去創建Message更加高效。

      • Handler.sendMessage(Message)方法最終會調用sendMessageAtTime方法。

        public boolean sendMessageAtTime(Message Message, long uptimeMillis) {
              // 1. 獲取Hndler中的消息隊列
              MessageQueue queue = mQueue;
              if (queue == null) {
                  RuntimeException e = new RuntimeException(
                          this + " sendMessageAtTime() called with no mQueue");
                  Log.w("Looper", e.getMessage(), e);
                  return false;
              }
              // 2. 將要發送消息和時間入隊
              return enqueueMessage(queue, Message, uptimeMillis);
          }

        總的來說,做了兩件事:

        1.獲取handler中的MessageQueue。

        2.調用enqueueMessage方法。

        enqueueMessage()方法代碼如下:

        private boolean enqueueMessage(MessageQueue queue, Message Message, long uptimeMillis) {
              // 1. 將Handler賦值給Message的target 
              Message.target = this;
              if (mAsynchronous) {
                  Message.setAsynchronous(true);
              }
              // 2. 將Message加入到消息隊列中(還有Handler)
              return queue.enqueueMessage(Message, uptimeMillis);
          }

        總的來說,做了兩件事:

        1.將handler賦值給Message.target。

        2.并且將Message放入MessageQueue中。

      2.3 線程間通信

      • 線程B的sendMessage流程執行完畢,至于線程A的Looper和Handler都已經創建好了,并且開始處理MessageQueue中的Message,還記得之前for循環中Message.target.dispatchMessage()方法嗎,其實這里的Message.target就是handler,而且dispatchMessage()方法的源碼如下:

        public void dispatchMessage(Message msg) {
           ..........
           handleMessage(msg);
        }
        在其中調用了handleMessage()方法,并且handleMessage()方法是個空方法,沒有內容。所以我們只用重寫這個方法就可以對線程B返回的消息進行處理了。

      3.一些問題

      • 為什么Activity主線程沒有執行Looper.prepare()和Looper.loop()?

        因為在ActivityThread的main方法中已經執行了這兩個方法。

      • 一個線程可以擁有幾個Looper?幾個Handler?

        一個線程只能擁有一個Looper,無數個Handler。

      • 如何從主線程發送消息給子線程?

        在子線程中先建立Looper,然后再建立Handler,依靠sendMessage和handleMessage即可。

       

      來自:http://www.jianshu.com/p/8862ab82d0f4

       

 本文由用戶 weibinbin 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!