Android:在doInBackground中取消AsyncTask时出现警告

3
我有一个问题:
我有一个主Activity请求另一个类的信息,该类从Web服务获取该信息,因此我在AsyncTask类上执行此操作。在数据加载时,主Activity显示一个ProgressDialog,我处理返回按钮,以便在按下时可以解除对话框,但现在我想取消AsyncTask。我创建了一个静态布尔变量,当按下返回按钮时为“true”,因此从AsyncTask的doInBackground方法中检查该变量是否为true,如果是,则取消AsyncTask:
@Override protected Void doInBackground(Integer... args) {      
  try {
        ....        
      if ( MainActivity.isDialogCancelled ){
        cancel(true);
        }
        ....
  } catch (Exception e) {
      ....
  } 
}

这似乎工作得很好,但是当我通过这种方式取消任务时,我看到一个 InterruptedException 警告,为什么会发生这种情况,并且我如何避免它们?我做错了什么吗?
这些是警告:
01-24 18:40:50.582: W/AsyncTask(22877): java.lang.InterruptedException
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1272)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:220)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.FutureTask.get(FutureTask.java:83)
01-24 18:40:50.582: W/AsyncTask(22877):     at android.os.AsyncTask$3.done(AsyncTask.java:196)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.FutureTask$Sync.innerCancel(FutureTask.java:294)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.FutureTask.cancel(FutureTask.java:76)
01-24 18:40:50.582: W/AsyncTask(22877):     at android.os.AsyncTask.cancel(AsyncTask.java:325)
01-24 18:40:50.582: W/AsyncTask(22877):     at android.os.AsyncTask$2.call(AsyncTask.java:185)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.FutureTask.run(FutureTask.java:138)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
01-24 18:40:50.582: W/AsyncTask(22877):     at java.lang.Thread.run(Thread.java:1019)

提前感谢您。


你确定你在正确的地方执行吗?你读过这个吗?取消任务 - 任务可以通过调用cancel(boolean)随时取消。调用此方法将导致后续对isCancelled()的调用返回true。调用此方法后,doInBackground(Object [])返回后将调用onCancelled(Object),而不是onPostExecute(Object)。为确保尽快取消任务,应尽可能从doInBackground(Object [])定期检查isCancelled()的返回值(例如,在循环内部)。 - Sergey Benner
抱歉,我没有放整个代码,但我已经捕获了它,但仍然在Logcat上显示警告,我更新了主贴中的代码,展示了try/catch的使用。 - Spike777
@ Sergey,我看了你复制的段落,它说我不能随时取消任务... 我能否从类的doInBackground方法中取消任务? - Spike777
这是另一个相关的问题,以防万一:https://dev59.com/pnE85IYBdhLWcg3whD7k - Sergey Benner
很高兴能帮忙,也很高兴你解决了它。 - Sergey Benner
显示剩余4条评论
4个回答

0

我相信这里的其他答案是正确的,但是为了更彻底地解释一下:

从你的AsyncTask回调到你的Activity方法以检查是否应该取消并不是一个好的做法。

正确的方式(根据文档):

通过调用cancel(boolean)方法可以随时取消任务。调用此方法将导致后续对isCancelled()的调用返回true。在调用此方法之后,在doInBackground(Object[])返回后,将调用onCancelled(Object)而不是onPostExecute(Object)为了尽快取消任务,您应该始终定期检查doInBackground(Object[])中的isCancelled()的返回值(如果可能的话,例如在循环内部)。

(加粗是我的)

所以,你的代码中有正确的基本思路,但是在想要取消异步任务时,不要设置Activity,而是调用cancel()方法。这会改变isCancelled()方法的返回值。然后,在doInBackground()方法内,你应该检查isCancelled()的值,并根据结果选择你的行为。

是的,虽然这可能不是理想的做法,但我曾经看到过可以从doInBackground()方法内部调用cancel(true);的可运行代码。


0

Cancel(false) 只是设置了异步任务的取消标志。如果您调用 cancel(true),它将设置异步任务的取消标志,并中断异步任务运行的后台线程。这就是 InterruptedException 可能来自的地方。


0
为什么不在 onPause() 中使用 asyncTask.cancel(true);

因为有时候你想要使用取消按钮或者安卓设备的返回按钮来取消下载或其他耗时任务。 - Sergey Benner
当我尝试在按下返回按钮时取消任务时,就会出现这个问题。 - Spike777

0

像任何其他的Thread一样,你必须用try/catch来包装它,并捕获InterruptedException异常。

此外,AsyncTask有一个函数cancel(boolean),请使用它代替你之前所做的操作,并且通过isCacneled()检查是否已经被取消了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接