Android AsyncTask 的實現及 cancel 方式


最近做一個功能需要用到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。這里貼一段我寫的代碼,有點點改動。

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的方法:

  1. 在ProgressDialog的setOnCancelListener里調用cancel(true);,表示如果ProgressDialog被cancel的話,也cancel掉AsyncTask;
  2. 在doInBackgroud方法中,判斷isCancelled()是否為真,如果真,那么就返回。

為什么在doInBackgroud中判斷?因為AsyncTask的重要工作都是在doInBackgroud中完成,它如果退出了,那么就意味着AsyncTask將被銷毀了。

具體在doInBackgroud的哪部分判斷是否要退出呢?這就需要根據程序的邏輯。一般在耗時操作的后面加上判斷!代碼中可以根據需要加多個這樣的判斷。


 

AsyncTask用於實現一些簡單的多線程任務確實非常簡單和好用,希望對大家有所幫助。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM