Android開發中,Handler用的非常多,因爲它和AsyncTask一樣是系統提供給我們的異步的通信機制。能夠將一些更新和別的不適合放在UI主線程的操作放到它們中去。
Handler的作用主要有兩個:一是在線程中發送消息, 二是獲取和處理消息。既可以發送消息sendEmptyMessage(int what) ,也可以發送指定的消息sendMessage(Message msg),還可以利用msg.obj的屬性去傳遞我們需要的參數甚至對象,使原本的通信機制更爲強大。
Handler發送消息的機制
Handler的出現,解決了在非UI主線程更新UI組件數據的問題。如上面提到的,我們使用handler.sendEmptyMessage(int what) 或者 sendMessage(Message msg)去發送消息,這個消息就會放去消息隊列MessageQueue中,MessageQueue是個先進先出的隊列,Handler按照這個順序一直從消息隊列MessageQueue中獲取消息Message,並且按照約定的方式去處理這些消息。下面是最簡單的發送空消息給handler去進行處理:
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg)
{
if(msg.what == 0x101)
{ //約定如何處理不同的msg消息
Log.i("print handler message", "msg.what = 0x101");
}
else if(msg.what == 0x201)
{
Log.i("print handler message", "msg.what = 0x201");
}
}
};
/**
* 發送空消息
*/
private void sendMessageA()
{
handler.sendEmptyMessage(0x101);
}
private void sendMessageB()
{
handler.sendEmptyMessage(0x201);
}
使用Handler的過程中,想必大家都會發現,如果在UI主線程中直接使用Handler去發送消息是沒問題的,但放在非主線程中就會報錯了。爲什麼呢?
Loop和MessageQueue的關係
這是因爲非主線程中並不會自動創建Looper對象。Looper是顧名思義,是一個“圈”,負責管理消息隊列MessgeQueue。Looper會不斷(一直循環到隊列中不再有message爲止)從MessageQueue中讀取消息並交給Handler去處理。因爲我們在主線程中handler發送消息,主線程是自動幫我們初始化創建一個Looper對象的,而且每個線程只能有一個Looper。因爲當然不允許同時有2個或以上的Looper對消息隊列讀取消息,這樣就會導致類似“鎖”的問題。也就是說,非UI主線程中,是不會自動幫我們創建這個Looper的。所以解決方法就是在發送消息前,先創建一個( prepare() ),然後開啓它( loop() )。這樣它才能正常的從消息隊列中讀取管理消息。還是用上面的例子,不過改成在子線程中去創建Handler並且處理。
{
private Handler mHandler;
@Override
public void run() {
// 創建Looper
Looper.prepare();
mHandler = new Handler(){
@Override
public void handleMessage(Message msg)
{
if(msg.what == 0x101)
{ //約定如何處理不同的msg消息
Log.i("print handler message", "msg.what = 0x101");
}
else if(msg.what == 0x201)
{
Log.i("print handler message", "msg.what = 0x201");
}
}
};
//啓動Looper,這樣它才能從消息隊列中讀取管理消息
Looper.loop();
}
}
private void sendMessgeInThread()
{
MessageThread mThread = new MessageThread();
//創建Handler
mThread.start();
mThread.mHandler.sendEmptyMessage(0x101);
}
總結三者的關係
從上面分個的來說明,我們已經知道Handler,Looper和MessageQueue分別的作用是什麼。這裏就總結下它們三者的關係:
情況一,在主線程中
創建Handler ----> 使用handler發送消息 ---> 消息被放入消息隊列MessageQueue中 ----> (主線程自動創建的)Looper負責不斷地從消息隊列中取出消息,交給Handler ---> Handler再次對不同的消息進行處理 ---> 消息message被處理完後,隨即被扔棄毀掉,然後繼續處理第二條到達的消息message,直到Looper已經將所有消息都讀取完。
情況二,在非主線程中
在上面的基礎上分別調用Looper.prepare() 和 Looper.loop()方法去創建和啓動Looer。創建Handler前調用Looper.prepare() ,創建完畢使用Looper.loop()。 剩下的收發消息和處理消息的過程和情況一是一樣的。