AsyncTask的cancel方法解读

当我们想要取消AsyncTask方法的运行的时候,我们可以调用cancel()方法来取消运行,但是cancel()方法并不会立即终止AsyncTask的运行,他只会将cancel标志位置位,同时对当前运行doInBackGround方法的线程执行interrupt()方法,也就是说AsyncTask并不会立即终止运行,如果我们想要终止AsyncTask的话,需要在doInBackGround方法中手动的调用isCancelled方法或者Thread.currentThread().isInterrupted()进行判断AsyncTask是否被终止运行。代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override
protected Boolean doInBackground(Void... params) {
try {
while (true) {
if(isCancelled())
break;
// if (Thread.currentThread().isInterrupted())
// break;
int downloadPercent = doDownload(); // 这是一个虚构的方法
publishProgress(downloadPercent);
if (downloadPercent >= 100) {
break;
}
}
} catch (Exception e) {
return false;
}
return true;
}

我们可以从源码上对cancel方法进行分析。

AsyncTask的cancel方法的源码如下所示:

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

可以看到cancel方法只是将mCancelled设置位true,同时调用了FutureTask的cancel(boolean mayInterruptIfRunnin)方法,FutureTask的cancel(boolean mayInterruptIfRunnin)方法也只是会对当前正在运行doInBackGround的线程调用interrupt()方法,我们知道线程的interrupt()方法并不会中断线程的运行,而是只会将线程的中断标志位置位,所以AsyncTask的cancel方法并不会取消当前正在运行的AsyncTask。

FutureTask的cancel方法的源码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
U.compareAndSwapInt(this, STATE, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally { // final state
U.putOrderedInt(this, STATE, INTERRUPTED);
}
}
} finally {
finishCompletion();
}
return true;
}

从源码可以看出,cancel方法会将cancel标志位置位,同时对当前运行doInBackGround方法的线程执行interrupt()方法,所以如果我们想要在调用过了cancel方法后,让当前正在运行的AsyncTask停止运行,需要在doInBackGround方法中手动的调用isCancelled方法或者Thread.currentThread().isInterrupted()来进行判断,从而做出相应的操作。

当调用cancel方法取消了AsyncTask运行之后,doInBackGround的返回结果,会传递到onCancel方法中,而onPostExecute并不会被调用。这一点从AsyncTaks的finish方法中可以看出:

AsyncTask的finish方法的源码如下所示:

1
2
3
4
5
6
7
8
 private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}

参考资料:

AsyncTask.cancel()的结束问题
AsyncTask中cancel方法的误读
Android AsyncTask cancel()方法的使用

FutureTask的cancel方法真的能停止掉一个正在执行的异步任务吗

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器