最近做一個功能需要用到AsyncTask。實現的過程很容易,但是在cancel的時候遇到了一點麻煩。找了很多地方終於找到了比較好的方法,這里跟大家分享一下。
根據Android Developer的介紹http://developer.android.com/intl/zh-CN/reference/android/os/AsyncTask.html :
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
AsyncTask其實是Android給開發者提供的一個簡單輕量級的多線程類,通過它我們可以很容易新建一個線程做一些耗時的操作,並在這個過程中更新UI。之所以說它輕量級,是因為缺少了直接使用Thread的靈活性。如果是很復雜的操作,還是建議通過Thread來操作,然后通過Broadcast的方式來更新UI。
使用AsyncTask的時候還需要注意,如果AsyncTask在運行過程中使用了某個activity,那么我們就需要在保證AsyncTask的運行過程中這個activity不被destory,或者是在activity的onDestory()方法里面cancel掉這個AsyncTask。但是,如果是一直不讓activity被destory的話,相當於不讓用戶切換界面,這個體驗其實時不好的。所以,我們最好使用ProgressDialog,讓用戶知道我們在努力完成他們的操作,為了讓用戶可以cancel這個操作,我們可以檢測ProgressDialog有沒有取消,如果取消了,那就cancel整個AsyncTask。
所以,我們總是會需要cancel AsyncTask。這里貼一段我寫的代碼,有點點改動。

1 private class OpenWebPortalTask extends AsyncTask<Void, Void, Void> { 2 private static final String DEFAULT_URL = "https://www.google.com"; 3 private ProgressDialog mProgressDialog = null; 4 private Activity mActivity; 5 6 public OpenWebPortalTask(Activity activity){ 7 mActivity = activity; 8 mProgressDialog = new ProgressDialog(mActivity); 9 mProgressDialog.setMessage(getString(R.string.open_aweb_portal)); 10 mProgressDialog.setCancelable(true); 11 mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { 12 13 @Override 14 public void onCancel(DialogInterface dialog) { 15 cancel(true); 16 } 17 }); 18 } 19 20 @Override 21 protected void onPreExecute(){ 22 mProgressDialog.show(); 23 } 24 25 @Override 26 protected Void doInBackground(Void... params) { 27 String schemeUrl = PropertyMgr.getInstance().getPortalURI(); 28 if (TextUtils.isEmpty(schemeUrl)) { 29 schemeUrl = DEFAULT_ANTI_THEFT_URL; 30 } 31 try { 32 String st = CredentialManager.getInstance().getServiceTicket(); 33 if(st != null) { 34 schemeUrl += "?st=" + st; 35 } 36 } catch (Exception e) { 37 SymLog.e(TAG, "Get Service Ticket failed."); 38 } 39 if(isCancelled()) { 40 return null; 41 } 42 Intent i = new Intent(Intent.ACTION_VIEW); 43 i.setData(Uri.parse(schemeUrl)); 44 startActivity(i); 45 return null; 46 } 47 48 @Override 49 protected void onPostExecute(Void v) { 50 mActivity.runOnUiThread(new Runnable() { 51 @Override 52 public void run() { 53 if (mProgressDialog != null) { 54 mProgressDialog.dismiss(); 55 mProgressDialog = null; 56 } 57 } 58 }); 59 } 60 }
這段代碼里面,
String st = CredentialManager.getInstance().getServiceTicket();
是個耗時操作,所以需要放在AsyncTask里面。例子中,在onPreExecute中顯示ProgressDialog,在onPostExecute中銷毀。
注意cancel AsyncTask的方法:
- 在ProgressDialog的setOnCancelListener里調用cancel(true);,表示如果ProgressDialog被cancel的話,也cancel掉AsyncTask;
- 在doInBackgroud方法中,判斷isCancelled()是否為真,如果真,那么就返回。
為什么在doInBackgroud中判斷?因為AsyncTask的重要工作都是在doInBackgroud中完成,它如果退出了,那么就意味着AsyncTask將被銷毀了。
具體在doInBackgroud的哪部分判斷是否要退出呢?這就需要根據程序的邏輯。一般在耗時操作的后面加上判斷!代碼中可以根據需要加多個這樣的判斷。
AsyncTask用於實現一些簡單的多線程任務確實非常簡單和好用,希望對大家有所幫助。