Android/AsyncTask:你还需要检查"isCancelled"(API 24)吗?



我的应用程序使用AsyncTask下载文件,同时显示带有"取消"按钮的ProgressDialog(我知道它已被弃用(。

根据这一点,您应该定期检查isCancelled()doInBackground,因为它不会自行中断doInBackgroundmytask.cancel(true)

我一开始没有检查就简单地取消了任务,并注意到它仍然停止doInBackground:根据我在按下"取消"按钮之前让它下载的时间,我在生成的文件中看到了不同的大小 - 从几 kb 到几 mb - 最终大小约为 9mb。

这怎么可能?你真的不用再打电话给isCancelled()了吗?

我的异步任务:

private class DownloadTask extends AsyncTask<String, String, String> {
protected void onPreExecute() {
progressdialog.setMessage("Preparing Download...");
progressdialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressdialog.setProgressNumberFormat(null);
progressdialog.setProgressPercentFormat(null);
progressdialog.setIndeterminate(true);
progressdialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
progressdialog.dismiss();
mytask.cancel(true);
}
});
progressdialog.show();
}
protected String doInBackground(String... bla) {
String error = download();
return error;
}
protected void onProgressUpdate(String... s) {
//....
}
protected void onPostExecute(String s) {
progressdialog.dismiss();
//....
}

根据这一点,你应该在doInBackground中检查isCancel(( 定期,因为 mytask.cancel(true( 不会中断 doInBackground 本身。

其实不是真的。

根据文档:

调用此方法后,应检查返回的值 isCancel(( 定期从 doInBackground(Object[]( 完成 尽早完成任务。

这意味着您还可以检查isCancelled()是否在启动AsyncTask时更早停止。

mytask.cancel(true( 无论如何都会停止执行。

让我们看看引擎盖下发生了什么

当您致电mytask.cancel(true)

public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}

mFuture在哪里FutureTask里面可以运行

然后mFuture.cancel称为:

public boolean cancel(boolean mayInterruptIfRunning) {
if (state != NEW)
return false;
if (mayInterruptIfRunning) {
if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, INTERRUPTING))
return false;
Thread t = runner;
if (t != null)
t.interrupt();
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED); // final state
}
else if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, CANCELLED))
return false;
finishCompletion();
return true;
}

runner只是在哪里

private volatile Thread runner;

由于它只是线程,让我们看看interrupt在您的情况下做了什么:

如果此线程在可中断的 I/O 操作中被阻塞 通道然后通道将被关闭,线程的中断状态 将被设置,并且线程将收到 ClosedByInterruptException。

因此,如果您download()方法使用InterruptibleChannelinterrupt将起作用。

换句话说,看起来您从来没有调用isCancelled()来中断AsyncTask=(,因为Thread.interrupt可以在您的情况下停止io阻塞操作。

最新更新