理想的方式来取消正在执行的AsyncTask

我使用AsyncTask在后台线程中运行远程audio文件获取和audio文件播放操作。 显示提取操作运行时间的可取消进度条。

我想在用户取消(决定)操作时取消/中止AsyncTask运行。 处理这种情况的理想方法是什么?

刚刚发现AlertDialogsboolean cancel(...); 我一直在使用,到处都是什么也没做。 大。
所以…

 public class MyTask extends AsyncTask<Void, Void, Void> { private volatile boolean running = true; private final ProgressDialog progressDialog; public MyTask(Context ctx) { progressDialog = gimmeOne(ctx); progressDialog.setCancelable(true); progressDialog.setOnCancelListener(new OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { // actually could set running = false; right here, but I'll // stick to contract. cancel(true); } }); } @Override protected void onPreExecute() { progressDialog.show(); } @Override protected void onCancelled() { running = false; } @Override protected Void doInBackground(Void... params) { while (running) { // does the hard work } return null; } // ... } 

如果你正在做计算

  • 您必须定期检查isCancelled()

如果你正在做一个HTTP请求

  • HttpGetHttpPost的实例保存在某个地方(例如公共字段)。
  • 调用cancel ,调用request.abort() 。 这将导致IOException抛出你的doInBackground

在我的情况下,我有一个连接器类,我在各种AsyncTasks中使用。 为了简单abortAllRequests ,我给这个类添加了一个新的abortAllRequests方法,并在调用cancel之后直接调用这个方法。

问题是AsyncTask.cancel()调用只调用任务中的onCancel函数。 这是你想要处理取消请求的地方。

这是我用来触发更新方法的一个小任务

 private class UpdateTask extends AsyncTask<Void, Void, Void> { private boolean running = true; @Override protected void onCancelled() { running = false; } @Override protected void onProgressUpdate(Void... values) { super.onProgressUpdate(values); onUpdate(); } @Override protected Void doInBackground(Void... params) { while(running) { publishProgress(); } return null; } } 

简单:不要使用AsyncTaskAsyncTask被devise用于快速结束(几十秒)的短操作,因此不需要被取消。 “audio文件播放”不符合条件。 您甚至不需要后台线程来播放普通的audio文件。

唯一的方法是检查isCancelled()方法的值,并在返回true时停止播放。

这是我写我的AsyncTask
关键是添加Thread.sleep(1);

 @Override protected Integer doInBackground(String... params) { Log.d(TAG, PRE + "url:" + params[0]); Log.d(TAG, PRE + "file name:" + params[1]); downloadPath = params[1]; int returnCode = SUCCESS; FileOutputStream fos = null; try { URL url = new URL(params[0]); File file = new File(params[1]); fos = new FileOutputStream(file); long startTime = System.currentTimeMillis(); URLConnection ucon = url.openConnection(); InputStream is = ucon.getInputStream(); BufferedInputStream bis = new BufferedInputStream(is); byte[] data = new byte[10240]; int nFinishSize = 0; while( bis.read(data, 0, 10240) != -1){ fos.write(data, 0, 10240); nFinishSize += 10240; **Thread.sleep( 1 ); // this make cancel method work** this.publishProgress(nFinishSize); } data = null; Log.d(TAG, "download ready in" + ((System.currentTimeMillis() - startTime) / 1000) + " sec"); } catch (IOException e) { Log.d(TAG, PRE + "Error: " + e); returnCode = FAIL; } catch (Exception e){ e.printStackTrace(); } finally{ try { if(fos != null) fos.close(); } catch (IOException e) { Log.d(TAG, PRE + "Error: " + e); e.printStackTrace(); } } return returnCode; } 

我们的全局AsyncTask类variables

 LongOperation LongOperationOdeme = new LongOperation(); 

而其中的KEYCODE_BACK动作则中断AsyncTask

  @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { LongOperationOdeme.cancel(true); } return super.onKeyDown(keyCode, event); } 

这个对我有用。

我不喜欢用不必要的cancel(true)来强制中断我的asynchronous任务,因为他们可能有资源被释放,比如closures套接字或文件stream,向本地数据库写数据等。另一方面,asynchronous任务拒绝完成自己的部分时间的情况下,例如有时当主要活动正在closures,我要求asynchronous任务完成从活动的onPause()方法。 所以这不是简单地调用running = false 。 我必须去混合解决scheme:都调用running = false ,然后给asynchronous任务几毫秒完成,然后调用cancel(false)cancel(true)

 if (backgroundTask != null) { backgroundTask.requestTermination(); try { Thread.sleep((int)(0.5 * 1000)); } catch (InterruptedException e) { e.printStackTrace(); } if (backgroundTask.getStatus() != AsyncTask.Status.FINISHED) { backgroundTask.cancel(false); } backgroundTask = null; } 

作为一个副作用, doInBackground()完成后,有时会调用onPostExecute()方法,有时会onPostExecute() 。 但至less可以保证asynchronous任务终止。