最近做一个功能需要用到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用于实现一些简单的多线程任务确实非常简单和好用,希望对大家有所帮助。