詳解Android Handler 機制 (二)源碼解析

ps:這是關於Android Handler 機制的第一篇文章,主要來講一下Handler的用法,本文儘可能概括徹底,若有缺漏,歡迎補充。java

Handler的主要做用是切換線程,以及隱式的充當接口回調的做用,當子線程網絡請求結束後,經過handler發送消息給主線程,這一點都很少說了。web

經常使用用法

先來貼一種最經常使用的用法:數組

private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            //...處理邏輯
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.bt_1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mHandler.sendEmptyMessage(MainActivity.HANDLER_MAIN_CODE);
            }
        });
複製代碼

這種方法是你們最經常使用的,使用Handler的匿名內部類,去覆寫handleMessage方法,來處理當消息到達時所作出的反應。這裏埋一個伏筆:markdown

報黃 這裏IDEA在提示可能會發生內存泄漏,具體爲何會發生內存泄漏,針對問題的具體分析以及最後封裝SafeHandler,我會在第三篇Handler文章中講述。網絡

Message

Message是Handler發送的消息的數據載體。

先看一下Message,Message用來承載數據,承載數據的實現是Message的幾個public的成員變量:ide

public int what;

    public int arg1;

    public int arg2;

    public Object obj;
  
複製代碼
  • what: 這是一個int類型的變量,一般用來在handleMessage處作判斷,當一個handler發送多條message時,用來辨別這是哪一條消息
  • arg1,arg2,當發送的Message須要承載的data是整數時,能夠簡單的使用這兩個參數來承載。
  • Obj,這是一個Object對象,由於有這個變量,咱們所能承載的data就多樣化了,只要是對象均可以經過message傳遞,List、數組等等。

另外Message還提供了經過Bundle來傳遞數據: Bundle也是一個數據載體,這裏就很少說了。函數

/** * Like getData(), but does not lazily create the Bundle. A null * is returned if the Bundle does not already exist. See * {@link #getData} for further information on this. * @see #getData() * @see #setData(Bundle) */
    public Bundle peekData() {
        return data;
    }

    /** * Sets a Bundle of arbitrary data values. Use arg1 and arg2 members * as a lower cost way to send a few simple integer values, if you can. * @see #getData() * @see #peekData() */
    public void setData(Bundle data) {
        this.data = data;
    }
複製代碼
Message池

Message中維持着一個Message池,因此一般咱們無需new Message(),能夠調用: Message message = Message.obtain();,節省內存空間。 。oop

Handler處理消息

Handler處理消息除了文章開頭所說到的一種,其實還有兩種: message的callback和handler的mCallback,一共有三種,爲何我能夠這麼說呢?下面上源碼post

public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
複製代碼

這個dispatchMessage()方法是在Lopper.loop方法的無限循環中調用的:this

for(;;) {
        ...
        msg.target.dispatchMessage(msg);
        ...
    }
複製代碼

這個msg就是咱們發送的消息,target就是咱們發送消息的handler。這裏看不懂的也不要緊,畢竟涉及到源碼,以後的第二篇會將。如今只須要知道這個dispathchMessage方法是在消息接收處調用的。而後繼續返回去看這個方法的內部實現。 這個方法經過三層if-else嵌套,也就規定了這三種Handler處理消息的方法的優先級: flowchart.png 能夠看到咱們經常使用的第三種方法,覆寫handlerMessage是優先級最低的。

msg.callback

既然是msg的一個屬性,那麼確定是經過msg承載callback來發送出去,先看一下callback的定義

@UnsupportedAppUsage
    /*package*/ Runnable callback;
複製代碼

這是一個Runnable,而後看一下handler的handleCallback(msg);方法:

private static void handleCallback(Message message) {
        message.callback.run();
}
複製代碼

這樣咱們就知道了,消息接受處在收到message以後,若是message的callback不爲空,就調用這個callback的run方法。下面看基於將事件包裝成Message的Runnable的兩種方法:

在Message的構造函數,或者obtain方法中直接傳入Runnable實例
private Handler mHandler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.bt_1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this, "消息接受後執行這段代碼,這段代碼運行在主線程"
                                                  ,Toast.LENGTH_SHORT).show();
                    }
                };
                Message message = Message.obtain(mHandler, runnable);
                mHandler.sendMessage(message);
            }
        });
}
複製代碼
mHandler.post(Runnable runnable)

相比於上一種方法,這種方法可能更加形象,將一個攜帶事件的Runnable,post到MesageQueue中,而後交給主線程執行:

private Handler mHandler = new Handler();


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.bt_1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
               
                
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this, "這段代碼交給主線程去執行", Toast.LENGTH_SHORT).show();
                    }
                });
            }
        });
複製代碼
mHandler.mCallback

這個方法其實和匿名內部類的寫法大同小異,只不過是把覆寫的handleMessage方法中的邏輯轉移到mHandler的mCallback中,下面直接上代碼:

Handler.Callback callback = new Handler.Callback() {
      @Override
      public boolean handleMessage(@NonNull Message msg) {
          Toast.makeText(MainActivity.this, "收到消息", Toast.LENGTH_SHORT).show();
          return true;
      }
  };

  private Handler mHandler = new Handler(callback);



  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      findViewById(R.id.bt_1).setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
              mHandler.sendMessage(Message.obtain());
          }
      });
}
複製代碼

注意handleMessage的返回時,若是返回true,那麼表示處理條消息,再也不向下執行。若是返回false,那麼表示沒有成功處理這條消息,接着向下執行,也是就執行Handler的handleMessage方法

Handler.Callback callback = new Handler.Callback() {
       @Override
       public boolean handleMessage(@NonNull Message msg) {
           Toast.makeText(MainActivity.this, "收到消息", Toast.LENGTH_SHORT).show();
           //...處理消息
           if (...) {
               return false;
           }
           return true;
       }
   };


   private Handler mHandler = new Handler(callback) {
       @Override
       public void handleMessage(@NonNull Message msg) {
           super.handleMessage(msg);
           Toast.makeText(MainActivity.this, 
                   "若是callback的handleMessage返回false,那麼接着執行這裏"
                   , Toast.LENGTH_SHORT).show();
       }
   };


   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

       findViewById(R.id.bt_1).setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               mHandler.sendMessage(Message.obtain());
           }
       });
}
複製代碼

總結

這樣終於把Handler的三種處理消息的用法搞清楚了,須要注意的是,第一種方法和其餘兩種是互斥的,只要Message的callback不爲空,那麼就執行callback中的run方法的邏輯,而不會執行handleMessage。

咱們須要知道的是,Handler機制在Android中的做用絕對不單單是給開發者切換線程,Handler機制在維持一個APP的正常運做。一個點擊事件,啓動一個Activity等等基礎功能,都離不開Handler。具體是如何運做的,就要看Handler機制的源碼了。


既然都看完了,你們點個贊再走呀

相關文章
相關標籤/搜索