Android Handler機制理解和AsyncTask使用小記
這是一篇淺入淺出的文章,對handler的使用和問題進行了一個總結,推薦看文章的你自己動手去練習,記憶和理解會更深刻一點。
- Handler的概念
我們先看一下Handler的百科介紹:
Handler主要用於非同步訊息的處理:當發出一個訊息之後,首先進入一個訊息佇列,傳送訊息的函式即刻返回,而另外一個部分在訊息佇列中逐一將訊息取出,
然後對訊息進行處理,也就是傳送訊息和接收訊息不是同步的處理。 這種機制通常用來處理相對耗時比較長的操作。
複製程式碼
比較難明白,我們先將概念拆分開理解,放下前面關於訊息的部分,先著重看最後一句:處理相對耗時較長的操作。
在Android中,主執行緒中不能執行耗時操作,不然可能會造成ANR等問題,只能在子執行緒來進行。比如需要下載一個圖片並顯示到介面上,那麼直接按照邏輯,下載圖片是可能耗時的操作,新建一個執行緒執行下載,然後將下載的圖片傳入介面對應的檢視中,程式碼如下:
new Thread(){
@Override
public void run() {
super.run();
final Bitmap bitmap = downloadImg();//下載圖片,返回bitmap
ivImg.setImageBitmap(bitmap);//傳入下載的圖片到檢視
}
};
複製程式碼
邏輯是正確的,但操作不對,程式無法執行。
因為在Android中,只有主執行緒能更新UI,所以主執行緒也叫UI執行緒,子執行緒中是不能更新UI的。這時候我們就可以用到Handler了,Handler可以作為Android更新UI的一套機制,正確的操作程式碼如下:
Handler handler = new Handler();
new Thread(){
@Override
public void run() {
super.run();
final Bitmap bitmap = downloadImg();//下載圖片,返回bitmap
handler.post(new Runnable() {
@Override
public void run() {
ivImg.setImageBitmap(bitmap);//通過Handler通知主執行緒更新UI
}
})
}
};
複製程式碼
可以看到,UI的操作放被到了Runnable物件中,然後利用Handler.post(Runnable)實現了UI的更新,可以簡單理解Handler為一個傳信者,將子執行緒中需要更新UI的資訊傳入主執行緒中進行。
這是Handler的一種使用方法,通過post(Runnable),第二種是sendMessage()方式,示例如下:
mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
if(msg==1){
tvText.setText("接收到訊息,更改UI");//通過Handler通知主執行緒更新UI
}
return false;
}
});
new Thread() {
@Override
public void run() {
super.run()
Message msg = new Message();
msg.what = 1;
mHandler.sendMessage(msg);
}
}.start();
複製程式碼
這裡可以看到,Handler實現了訊息的傳出、訊息的接收與處理,其實在post(Runnable)方法中,Runnable物件本身也是作為一個訊息傳出的,再次回顧Handler的概念:
Handler主要用於非同步訊息的處理:當發出一個訊息之後,首先進入一個訊息佇列,傳送訊息的函式即刻返回,而另外一個部分在訊息佇列中逐一將訊息取出,
然後對訊息進行處理,也就是傳送訊息和接收訊息不是同步的處理。 這種機制通常用來處理相對耗時比較長的操作。
複製程式碼
我們知道了Handler是一個關於訊息非同步處理的任務機制,對於非同步和同步,舉個例子說明
- 同步處理:買傢俱→在商場選擇好傢俱→等待工人裝車→送到家中安裝傢俱→處理其他事物
- 非同步處理:買傢俱→在網上買好傢俱→等待過程中處理其他事物→傢俱送到安裝傢俱
可以看出,非同步操作最大的特點是,不會阻礙呼叫者的工作,無需等待前一個操作做完才做下一個操作,對於耗時的操作,使用非同步來處理是非常有必要的。
那麼在進行非同步操作的過程中,需要一個訊息的傳遞者來指導各部分進行操作,在剛才網購的例子裡,這個傳遞者是網上商城,而在Android的UI處理中,這個訊息傳遞者就是Handler。
其他一些Handler的使用方法
- handler.post()
- handler.postDelayed()
- handler.sendMessage();
- handler.sendEmptyMessage();
- handler.removeCallback(runnable)
-
AsyncTask非同步任務的使用
前面介紹了Handler+Thread進行非同步訊息處理,Android對此有封裝一個更好用的元件——AsyncTask。原理是相同的,但相比Handler+Thread更加簡單易用。
使用時首先需要構建AsyncTask子類的泛型引數,AsyncTask<Params,Progress,Result>是一個抽象類,通常用於被繼承,繼承AsyncTask需要指定如下三個泛型引數:
- Params:啟動任務時輸入的引數型別.
- Progress:後臺任務執行中返回進度值的型別.
- Result:後臺任務執行完成後返回結果的型別.
在構建AsyncTask子類主要有如下幾個回撥方法:
- doInBackground:必須重寫,非同步執行後臺執行緒要完成的任務,耗時操作將在此方法中完成.
- onPreExecute:執行後臺耗時操作前被呼叫,通常用於進行初始化操作.
- onPostExecute:當doInBackground方法完成後,系統將自動呼叫此方法,並將doInBackground方法返回的值傳入此方法.通過此方法進行UI的更新.
- onProgressUpdate:當在doInBackground方法中呼叫publishProgress方法更新任務執行進度後,將呼叫此方法.通過此方法我們可以知曉任務的完成進度.