理想的方式来取消正在执行的AsyncTask
我使用AsyncTask
在后台线程中运行远程audio文件获取和audio文件播放操作。 显示提取操作运行时间的可取消进度条。
我想在用户取消(决定)操作时取消/中止AsyncTask
运行。 处理这种情况的理想方法是什么?
刚刚发现AlertDialogs
的boolean 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请求 :
- 将
HttpGet
或HttpPost
的实例保存在某个地方(例如公共字段)。 - 调用
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; } }
简单:不要使用AsyncTask
。 AsyncTask
被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任务终止。