在Android中實現異步任務機制有兩種方式,Handler和AsyncTask。 本篇就說說AsyncTask的異步實現。
1、什么時候使用 AsnyncTask
在上一篇文章已經說了,主線程主要負責控制UI頁面的顯示、更新、交互等。 為了有更好的用戶體驗,UI線程中的操作要求越短越好。
我們把耗時的操作(例如網絡請求、數據庫操作、復雜計算)放到單獨的子線程中操作,以避免主線程的阻塞。但是在子線程中不能更新UI界面,這時候需要使用handler。
但如果耗時的操作太多,那么我們需要開啟太多的子線程,這就會給系統帶來巨大的負擔,隨之也會帶來性能方面的問題。在這種情況下我們就可以考慮使用類AsyncTask來異步執行任務,不需要子線程和handler,就可以完成異步操作和刷新UI。
不要隨意使用AsyncTask,除非你必須要與UI線程交互.默認情況下使用Thread即可,要注意需要將線程優先級調低.AsyncTask適合處理短時間的操作,長時間的操作,比如下載一個很大的視頻,這就需要你使用自己的線程來下載,不管是斷點下載還是其它的.
2、AsnyncTask原理
AsyncTask主要有二個部分:一個是與主線程的交互,另一個就是線程的管理調度。雖然可能多個AsyncTask的子類的實例,但是AsyncTask的內部Handler和ThreadPoolExecutor都是進程范圍內共享的,其都是static的,也即屬於類的,類的屬性的作用范圍是CLASSPATH,因為一個進程一個VM,所以是AsyncTask控制着進程范圍內所有的子類實例。
AsyncTask內部會創建一個進程作用域的線程池來管理要運行的任務,也就就是說當你調用了AsyncTask的execute()方法后,AsyncTask會把任務交給線程池,由線程池來管理創建Thread和運行Therad。
3、AsyncTask介紹
Android的AsyncTask比Handler更輕量級一些(只是代碼上輕量一些,而實際上要比handler更耗資源),適用於簡單的異步處理。
Android之所以有Handler和AsyncTask,都是為了不阻塞主線程(UI線程),因為UI的更新只能在主線程中完成,因此異步處理是不可避免的。
AsyncTask:對線程間的通訊做了包裝,是后台線程和UI線程可以簡易通訊:后台線程執行異步任務,將result告知UI線程。
使用AsyncTask分為兩步:
① 繼承AsyncTask類實現自己的類
public abstract class AsyncTask<Params, Progress, Result> {
Params: 輸入參數,對應excute()方法中傳遞的參數。如果不需要傳遞參數,則直接設為void即可。 Progress:后台任務執行的百分比 Result:返回值類型,和doInBackground()方法的返回值類型保持一致。
②復寫方法
最少要重寫以下這兩個方法:
-
doInBackground(Params…)
在子線程(其他方法都在主線程執行)中執行比較耗時的操作,不能更新UI,可以在該方法中調用publishProgress(Progress…)來更新任務的進度。Progress方法是AsycTask中一個final方法只能調用不能重寫。
-
onPostExecute(Result)
使用在doInBackground 得到的結果處理操作UI, 在主線程執行,任務執行的結果作為此方法的參數返回。
有時根據需求還要實現以下三個方法: -
onProgressUpdate(Progress…)
可以使用進度條增加用戶體驗度。 此方法在主線程執行,用於顯示任務執行的進度。
-
onPreExecute()
這里是最終用戶調用Excute時的接口,當任務執行之前開始調用此方法,可以在這里顯示進度對話框。
-
onCancelled()
用戶調用取消時,要做的操作
4、AsyncTask示例
按照上面的步驟定義自己的異步類:
public class MyTask extends AsyncTask<String, Integer, String> { //執行的第一個方法用於在執行后台任務前做一些UI操作 @Override protected void onPreExecute() { } //第二個執行方法,在onPreExecute()后執行,用於后台任務,不可在此方法內修改UI @Override protected String doInBackground(String... params) { //處理耗時操作 return "后台任務執行完畢"; } /*這個函數在doInBackground調用publishProgress(int i)時觸發,雖然調用時只有一個參數 但是這里取到的是一個數組,所以要用progesss[0]來取值 第n個參數就用progress[n]來取值 */ @Override protected void onProgressUpdate(Integer... progresses) { //"loading..." + progresses[0] + "%" super.onProgressUpdate(progress); } /*doInBackground返回時觸發,換句話說,就是doInBackground執行完后觸發 這里的result就是上面doInBackground執行后的返回值,所以這里是"后台任務執行完畢" */ @Override protected void onPostExecute(String result) { } //onCancelled方法用於在取消執行中的任務時更改UI @Override protected void onCancelled() { } }
在主線程申明該類的對象,調用對象的execute()函數開始執行。
MyTask t= new MyTask(); t.execute();//這里沒有參數
5、使用AsyncTask需要注意的地方
-
AsnycTask內部的Handler需要和主線程交互,所以AsyncTask的實例必須在UI線程中創建
-
AsyncTaskResult的doInBackground(mParams)方法執行異步任務運行在子線程中,其他方法運行在主線程中,可以操作UI組件。
-
一個AsyncTask任務只能被執行一次。
-
運行中可以隨時調用AsnycTask對象的cancel(boolean)方法取消任務,如果成功,調用isCancelled()會返回true,並且不會執行 onPostExecute() 方法了,而是執行 onCancelled() 方法。
-
對於想要立即開始執行的異步任務,要么直接使用Thread,要么單獨創建線程池提供給AsyncTask。默認的AsyncTask不一定會立即執行你的任務,除非你提供給他一個單獨的線程池。如果不與主線程交互,直接創建一個Thread就可以了。