Handler解析記錄

前言

Handler是Android一個很基礎的東西了,面試的時候常常問,並且都是問內部原理,是如何傳遞消息的,如今在此記錄一下Handler的消息傳遞機制面試

Handler的用法

Handler的用法很簡單,就是直接new一個Handler,而後對這個對象發送消息 主線程中:bash

Message msg = new Message();
 handler.sendMessage(msg);

 public Handler handler= new Handler(){
       @Override
       public void handleMessage(Message msg) {
           super.handleMessage(msg);
       }
   };
複製代碼

異步線程中:異步

Message msg = new Message();
        handler.sendMessage(msg);


        new Thread(){
            @Override
            public void run() {
                super.run();
                Looper.prepare();

                handler=new Handler(){
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                    }
                };

                Looper.loop();
            }
        };
複製代碼

Handler的消息傳遞順序

Handler傳遞消息大概有如下三個步驟:ide

  1. Looper.prepare();方法會綁定當前線程,並建立一個MessageQueue
  2. handler發送消息到MessageQueue
  3. Looper.loop();這裏會無限輪詢去獲取MessageQueue中的消息,若是獲取到了消息,則經過handler的dispatchMessage()方法將消息傳遞出去

源碼追蹤Handler消息傳遞的三個步驟

  1. Looper.prepare();oop

    • 這個方法的做用是綁定當前線程post

    • 建立一個MessageQueue this

      在這裏插入圖片描述
      在這裏插入圖片描述

      經過上面的代碼,咱們能夠看到Looper經過調用prepare方法實現了建立一個Looper,而且經過ThreadLocal綁定當前線程和建立了一個MessageQueuespa

  2. handler發送消息到MessageQueue線程

    咱們發送消息的時候都是經過handler的send或者post之類的方法來發送消息,可是無論是經過send類型的或者是post類型的,他們都會調用到Handler中的enqueueMessage()方法,這個不貼代碼了,太多了,能夠自行追蹤一下,能夠發現Handler發送消息的方法最終都會調用到sendMessageAtTime()方法,而後在該方法中判斷是否存在MessageQueue,若是存在就調用enqueueMessage()方法3d

    在這裏插入圖片描述
    在這裏插入圖片描述

  3. Looper.loop(); 該方法上面說了是無限輪詢的去MessageQueue中獲取消息,而後拿到消息後,再經過handler將消息發送回去 代碼太多就截取loop()方法中關鍵的地方吧

    在這裏插入圖片描述
    這裏咱們能夠關注兩個點,第一,經過當前的Looper將第一步中在構造中建立的MessageQueue獲取到;第二調用MessageQueue的next方法取出消息(在next方法中還進行了時間的判斷,這裏是指延遲發送的,只有達到時間了,纔會喚醒該消息,進行發送)
    在這裏插入圖片描述
    這裏的msg.target就是Handler,在前面說過了每一個handler在發送消息的時候最終都會通過enqueueMessage()方法,在enqueueMessage()方法中就將當前的handler賦值給了msg.target,而後就是handler調用了dispatchMessage()方法將消息發送出去,而且判斷當前的callback是否爲空,若是不爲空,則調用handlerMessage()方法將消息發出去,咱們在new Handler()時重寫的HandlerMessage()方法就是這個了;

    在這裏插入圖片描述

主線程中的Handler與異步線程中的Handler

在主線程中,咱們沒有調用過Looper.prepare()和Looper.loop()方法,照樣能夠直接給handler發送消息,這是由於在主線程操做管理者(ActivityThread)中已經幫咱們寫好了Looper.prepare()和Looper.loop()方法(注意:loop是一個死循環,loop後面的代碼不會執行,因此從圖片中咱們能夠看到,若是loop後面的執行了,那就報錯了),並且主線程中的Looper是不能夠退出的,退出就會報錯

在這裏插入圖片描述

Handler引發的內存泄漏

將 Handler 定義成靜態的內部類,在內部持有 Activity 的弱引用,並及時移除全部消息。

private static class SafeHandler extends Handler {
 
    private WeakReference<HandlerActivity> ref;

    public SafeHandler(HandlerActivity activity) {
        this.ref = new WeakReference(activity);
     }
 
    @Override
    public void handleMessage(final Message msg) {
        HandlerActivity activity = ref.get();
        if (activity != null) {
            activity.handleMessage(msg);
        }
    }
}

//在Activity中移除消息
Override
protected void onDestroy() {
  safeHandler.removeCallbacksAndMessages(null);
  super.onDestroy();
}
複製代碼

總結

以上是記錄Handler的消息發送機制,以及避免由Handler引發的內存泄漏的解決辦法,總結不徹底確定還有其餘的沒有記錄到的,但願網友們指出!

相關文章
相關標籤/搜索