Android/AsyncTask:还要检查"isCancelled"(API24)吗?
Android/AsyncTask: Do you still have to check "isCancelled" (API 24)?
我的应用程序使用 AsyncTask
下载文件,同时显示带有 "Cancel" 按钮的 ProgressDialog
(我知道它已被弃用)。
根据 this,您应该定期检查 doInBackground
中的 isCancelled()
,因为 mytask.cancel(true)
不会自行中断 doInBackground
。
我一开始没有检查就取消了任务,发现它仍然停止 doInBackground
:根据我在按下 "Cancel" 按钮之前让它下载的时间长短,我看到了不同的大小在生成的文件中 - 从几 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();
//....
}
According to this you should check isCancelled() in doInBackground
periodically because mytask.cancel(true) won't interrupt
doInBackground on its own.
事实并非如此。
After invoking this method, you should check the value returned by
isCancelled() periodically from doInBackground(Object[]) to finish the
task as early as possible.
这意味着您可以 另外 检查 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
在你的情况下做了什么:
If this thread is blocked in an I/O operation upon an interruptible
channel then the channel will be closed, the thread's interrupt status
will be set, and the thread will receive a ClosedByInterruptException.
因此,如果您的 download()
方法使用 InterruptibleChannel
interrupt
将起作用。
换句话说,您似乎从来不需要调用 isCancelled()
来中断 AsyncTask
=) 因为 Thread.interrupt
可以在您的情况下停止 io 阻塞操作。
我的应用程序使用 AsyncTask
下载文件,同时显示带有 "Cancel" 按钮的 ProgressDialog
(我知道它已被弃用)。
根据 this,您应该定期检查 doInBackground
中的 isCancelled()
,因为 mytask.cancel(true)
不会自行中断 doInBackground
。
我一开始没有检查就取消了任务,发现它仍然停止 doInBackground
:根据我在按下 "Cancel" 按钮之前让它下载的时间长短,我看到了不同的大小在生成的文件中 - 从几 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();
//....
}
According to this you should check isCancelled() in doInBackground periodically because mytask.cancel(true) won't interrupt doInBackground on its own.
事实并非如此。
After invoking this method, you should check the value returned by isCancelled() periodically from doInBackground(Object[]) to finish the task as early as possible.
这意味着您可以 另外 检查 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
在你的情况下做了什么:
If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.
因此,如果您的 download()
方法使用 InterruptibleChannel
interrupt
将起作用。
换句话说,您似乎从来不需要调用 isCancelled()
来中断 AsyncTask
=) 因为 Thread.interrupt
可以在您的情况下停止 io 阻塞操作。