Android異步任務處理
Android主線程(UI線程)不准執行異步任務,以免阻塞主線程。所以異步任務一定是在工作線程中完成,然后,通知主線程,進行返回結果,刷新UI等操作。
1、使用handler
使用handler可以很方便的進行主線程與工作線程的交互,當在線程里創建handler時,handler會自動綁定當前線程
重寫@Overried handlerMessage(),可以處理Message。
/**
*
*
*/
@Override
public void handleMessage(@NonNull Message msg) {
//根據msg.what執行相應命令(不設置,默認為0),msg.obj攜帶結果信息
switch (msg.what){
case 0:
…執行相應操作
break;
default:
}
}
常見的做法是在主線程中創建handler,在工作線程中處理完異步任務后發送Message,主線程重寫handlerMessage()里處理返回結果。
使用handler進行異步處理時,容易產生內存泄漏問題,固然可以通過將handler設置為靜態內部類,解決這個問題,但是將handler設置為靜態內部類后就無法引用內部成員變量。內存泄漏原因是activity要銷毀時,消息隊列里消息沒處理完,Message Queue默認引用handler,handler默認引用activity。
所以推薦的做法是:在onDestory()階段,清空消息隊列,取消handler引用。
protected void onDestroy() {
super.onDestroy();
if (mHandler != null) {
mHandler.removeCallbacksAndMessages(null);
mHandler = null;
}
}
(參考資料)
https://juejin.im/post/5a692377518825734e3e71ab
2、使用IntentService(異步任務處理服務)
使用IntentService,IntentService其實是封裝了service和handler的類,所以和上述類似,它處理消息是在@Overried
onHandleIntent()
根據傳入的intent執行相應的異步處理
IntentService其內部維護一個消息隊列,根據傳入的intent的時間,先來先服務。前一項服務沒處理完,后一項服務不會開始。
官網推薦的IntentService與Activity通信的方式是localBroadcast。
相比handler,其主要優點在於可以在后台執行,不受Activity生命周期影響。(只能通過startActivity()啟動IntentService,可以像普通service一樣綁定activity,通過Binder通信)
如果說消息隊列里沒消息了,那么service會暫停,內存不夠的情況下有可能被系統殺死。
3、使用handlerThread
聽名字就可以猜出來,一個繼承了Thread的handler處理類,其內部維護一個消息隊列,重寫@Overried handlerMessage()處理消息,對應於主線程。
一些情況下,我們需要工作線程處理消息,那么我們就創建一個handlerThread,根據傳入消息,執行異步任務。
比較好的理解方式:主線程可以有個handleMessage,我工作線程也想有個,但是新建一個Thread,設置Looper什么的太麻煩,於是新建一個HandlerThread,一些准備工作都做好了,像主線程一樣創建handler綁定線程,重寫@Overried handlerMessage()處理消息就OK了!
其實創建一個Hhread,手動引用創建一個Looper的效果和創建HandlerThread效果一樣
需要注意:為了防止內存泄漏,要像在主線程里的handler一樣,在onDestory()階段,
清空消息隊列,取消handler引用。
/**
*
* workHandler: 綁定工作線程的handler
* mHandler:綁定主線程的handler
*/
protected void onDestroy() {
super.onDestroy();
if (workHandler != null) {
workHandler.removeCallbacksAndMessages(null);
workHandler = null;
}
if (mHandler != null) {
mHandler.removeCallbacksAndMessages(null);
mHandler = null;
}
}
4、使用AsyncTask
使用AsyncTask,AsyncTask是一個封裝好的輕量級異步任務處理類,輕量級,顧名思義,一些重量級的異步任務還是自己搞個實現,大部分場景下,AsyncTask夠用了。
相比AsyncTask,我更喜歡使用handler+Thread解決異步任務。
一個異步任務使用AsyncTask很方便,多個異步任務使用handler+thread更好。
有一種場景非常適合使用AsyncTask:需要顯示進度值的場景,使用這個封裝好的類,方便理解,節省代碼
輕量級異步處理AsyncTask
/**
* 步驟1:創建AsyncTask子類
* 注:
* a. 繼承AsyncTask類
* b. 為3個泛型參數指定類型;若不使用,可用java.lang.Void類型代替
* c. 根據需求,在AsyncTask子類內實現核心方法
*/
private class MyTask extends AsyncTask<Params, Progress, Result> {
....
// 方法1:onPreExecute()
// 作用:執行 線程任務前的操作
// 注:根據需求復寫
@Override
protected void onPreExecute() {
...
}
// 方法2:doInBackground()
// 作用:接收輸入參數、執行任務中的耗時操作、返回 線程任務執行的結果
// 注:必須復寫,從而自定義線程任務
@Override
protected String doInBackground(String... params) {
...// 自定義的線程任務
// 可調用publishProgress()顯示進度, 之后將執行onProgressUpdate()
publishProgress(count);
}
// 方法3:onProgressUpdate()
// 作用:在主線程 顯示線程任務執行的進度
// 注:根據需求復寫
@Override
protected void onProgressUpdate(Integer... progresses) {
...
}
// 方法4:onPostExecute()
// 作用:接收線程任務執行結果、將執行結果顯示到UI組件
// 注:必須復寫,從而自定義UI操作
@Override
protected void onPostExecute(String result) {
...// UI操作
}
// 方法5:onCancelled()
// 作用:將異步任務設置為:取消狀態
@Override
protected void onCancelled() {
...
}
}
/**
* 步驟2:創建AsyncTask子類的實例對象(即 任務實例)
* 注:AsyncTask子類的實例必須在UI線程中創建
*/
MyTask mTask = new MyTask();
/**
* 步驟3:手動調用execute(Params... params) 從而執行異步線程任務
* 注:
* a. 必須在UI線程中調用
* b. 同一個AsyncTask實例對象只能執行1次,若執行第2次將會拋出異常
* c. 執行任務中,系統會自動調用AsyncTask的一系列方法:onPreExecute() 、doInBackground()、onProgressUpdate() 、onPostExecute()
* d. 不能手動調用上述方法
*/
mTask.execute();
注意:doInBackground()是在工作線程運行的方法,不能調用UI;onPostExecute()是在主UI運行的方法,可以更新UI
總結一下
Thread + 消息機制
優點:使用非常靈活(自己手寫的代碼一般也是最多的)一般只在Activity里使用,主線程,工作線程均可實現自己的handler機制
缺點:Activity掛了,也就跟着掛了,需要后台運行那就用IntentService
IntentService + ResultReceiver
優點:在后台運行,一般情況下不會被殺死
缺點:官網推薦采用localBroadcast通信,手寫代碼較多。
AsyncTask
優點:被封裝過,需要顯示進度條的情況下非常方便,可以串行,也可以並行
缺點:沒那么靈活,只能在主線程里創建