ps:這是關於Android Handler 機制的第一篇文章,主要來說一下Handler的用法,本文儘量歸納完全,如有缺漏,歡迎補充。
Handler的主要作用是切換線程,以及隱式的充當接口回調的作用,當子線程網絡請求結束後,通過handler發送消息給主線程,這一點都不多說了。
常用用法
先來貼一種最常用的用法:
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方法,來處理當消息到達時所做出的反應。這裏埋一個伏筆:
這裏IDEA在提示可能會發生內存泄漏,具體爲什麼會發生內存泄漏,針對問題的具體分析以及最後封裝SafeHandler,我會在第三篇Handler文章中講述。
Message
Message是Handler發送的消息的數據載體。
先看一下Message,Message用來承載數據,承載數據的實現是Message的幾個public的成員變量:
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();
,節省內存空間。
。
Handler處理消息
Handler處理消息除了文章開頭所說到的一種,其實還有兩種:
message的callback和handler的mCallback,一共有三種,爲什麼我可以這麼說呢?下面上源碼
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方法的無限循環中調用的:
for(;;) {
...
msg.target.dispatchMessage(msg);
...
}
這個msg就是我們發送的消息,target就是我們發送消息的handler。這裏看不懂的也沒關係,畢竟涉及到源碼,之後的第二篇會將。現在只需要知道這個dispathchMessage方法是在消息接收處調用的。然後繼續返回去看這個方法的內部實現。
這個方法通過三層if-else嵌套,也就規定了這三種Handler處理消息的方法的優先級:
可以看到我們常用的第三種方法,覆寫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方法。下面看一個例子:
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.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機制的源碼了。