当用户取消(决定不进行)操作时,我想取消/中止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
方法,并在调用cancel
之后直接调用此方法。
HttpGet.abort()
,否则会出现 android.os.NetworkOnMainThreadException
异常。 - Heath Borderscancel(true)
不应该中断请求吗?根据文档:如果任务已经开始,则mayInterruptIfRunning参数确定执行此任务的线程是否应该被中断以尝试停止任务。
- StoroHttpURLConnection.disconnect();
- Oded Breinercancel(true)
。我使用了它并且它有效。 - S.M.Mousavirequest.abort()
是什么? - user25问题在于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;
}
}
running
标志。AsyncTask 有一个内部标志,用于在任务被取消时设置。将 while (running)
替换为 while (!isCancelled())
。在这种简单情况下,您不需要覆盖 onCancelled()
方法。参考链接:http://developer.android.com/reference/android/os/AsyncTask.html#isCancelled() - ToolmakerSteve简单来说:不要使用 AsyncTask
。 AsyncTask
设计用于短时间内迅速结束的操作(数十秒),因此不需要取消操作。"音频文件播放" 并不符合这一条件。在普通音频文件播放中,甚至不需要后台线程。
onPostExecute()
中测试该变量以确定是否应该继续进行工作。 - CommonsWare@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;
}
唯一的方法是通过检查isCancelled()方法的值,并在返回true时停止播放。
我们的全局AsyncTask类变量
LongOperation LongOperationOdeme = new LongOperation();
一个中断AsyncTask的KEYCODE_BACK操作
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
LongOperationOdeme.cancel(true);
}
return super.onKeyDown(keyCode, event);
}
这对我来说可以运行。
我不喜欢不必要地强制中断我的异步任务,例如使用cancel(true)
,因为它们可能有需要释放的资源,例如关闭套接字或文件流、将数据写入本地数据库等。另一方面,我也遇到过异步任务拒绝在某些情况下结束的情况,例如当主活动正在关闭并且我从活动的onPause()
方法内请求异步任务结束时。因此,这不仅仅是调用running = false
的问题。我必须采取混合解决方案:既调用running = false
,然后给异步任务几毫秒的时间来完成,然后再调用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()
完成后,有时会调用 onCancelled()
方法,有时会调用 onPostExecute()
方法。但至少异步任务终止是有保障的。public class MyTask extends AsyncTask<Void, Void, Void> {
private volatile boolean running = true;
//...
@Override
protected void onCancelled() {
running = false;
}
@Override
protected Void doInBackground(Void... params) {
// does the hard work
while (running) {
// part 1 of the hard work
}
while (running) {
// part 2 of the hard work
}
// ...
while (running) {
// part x of the hard work
}
return null;
}
// ...
对于选项 (b.),你在“doInBackground”中的代码会像这样:
public class MyTask extends AsyncTask<Void, Void, Void> {
//...
@Override
protected Void doInBackground(Void... params) {
// part 1 of the hard work
// ...
if (isCancelled()) {return null;}
// part 2 of the hard work
// ...
if (isCancelled()) {return null;}
// ...
// part x of the hard work
// ...
if (isCancelled()) {return null;}
}
// ...
while(running)
替换为while(!isCancelled())
,就像其他人在评论中说的那样,但不要改变原来的意思。 - matt5784