【问题标题】:Timing of execution of AsyncTask onCancelled() and AsyncTask.doInBackground()AsyncTask onCancelled() 和 AsyncTask.doInBackground() 的执行时机
【发布时间】:2011-07-10 13:20:06
【问题描述】:

根据AsyncTask.cancel method 的 Android 参考,明确定义了 onCancelled() 和 doInBackground() 之间的时间:

调用此方法将导致在 doInBackground(Object[]) 返回后在 UI 线程上调用 onCancelled(Object)。调用此方法保证永远不会调用 onPostExecute(Object)

但是,查看我的 logcat,我可以看到 onCancelled() 方法在 doInBackground() 方法返回之前执行。

07-10 12:38:57.000: VERBOSE/AsyncTask(7473): doInBackground entered
07-10 12:38:57.000: VERBOSE/AsyncTask(7473): AsyncTask attempting to take the lock
07-10 12:38:57.000: VERBOSE/AsyncTask(7473): AsyncTask got the lock
07-10 12:38:57.420: VERBOSE/AsyncTask(7473): Start Item[0].state = 0
07-10 12:38:57.933: VERBOSE/AsyncTask(7473): onProgressUpdate entered
07-10 12:38:57.940: VERBOSE/AsyncTask(7473): onProgressUpdate exited
07-10 12:38:58.320: VERBOSE/(7473): onCancelListener cancelling AsyncTask
07-10 12:38:58.400: VERBOSE/AsyncTask(7473): onCancelled entered
07-10 12:38:58.400: VERBOSE/AsyncTask(7473): onCancelled exited
07-10 12:38:58.560: VERBOSE/AsyncTask(7473): Started checking file URL
07-10 12:38:58.601: VERBOSE/FileHost(7473): checkFile entered
07-10 12:38:58.641: VERBOSE/FileHost(7473): checkFile checking URI
07-10 12:38:58.691: DEBUG/dalvikvm(7473): threadid=19 wakeup: interrupted
07-10 12:38:58.710: VERBOSE/AsyncTask(7473): AsyncTask released the lock
07-10 12:38:58.710: VERBOSE/AsyncTask(7473): doInBackground exited

使用调试器并在 onCancelled() 方法和 doInBackground() 方法结束处设置断点,我还可以看到 onCancelled() 在 doInBackground() 结束之前被调用。

我是否在 AsyncTask 中错误编码了某些内容,从而导致 Android 参考和我的应用程序行为之间的行为差​​异?

为 Gallal 添加了一些代码:

@Gallal,Activity 包含这段代码。

private class OnCancelListener implements AddUrlDialog.CancelListener {
  @Override
  public void cancel() {
    if (addUrlInProgress == true) {
      addUrlInProgress = false;
      Log.v(TAG, "onCancelListener cancelling AsyncTask");
      addUrlControl.stopUpdates(true);
      AddUrlDialog.dismiss();
    }
  } 
}

AsyncTask.cancel 在 addUrlControl.stopUpdates() 方法中被调用。

public void stopUpdates(boolean cleanupLists) {
  if (asyncTaskExited != true) {
      cancelRequest = true; 
        addUrlAsyncTask.cancel(true);
        //TEST httpRequest.abort(); // Also sends an abort to the HTTP request
  }
}

AsyncTask doInBackground 方法如下所示。

@Override
protected Void doInBackground(Void... v) {
  Log.v(TAG, "doInBackground entered");

    netConn = addUrlControl.myApp.getNetConn();
    client = netConn.getHttpClient();

    try {
      doInBackgroundBody();
  } catch (Throwable t) {
      Log.e(TAG, "doInBackgroundBody threw an exception: ", t);
  } finally {
      addUrlControl.myApp.releaseNetConn();
  }

    Log.v(TAG, "doInBackground exited");        
    return null;
}

【问题讨论】:

  • 日志消息的顺序总是一样的吗?您正在从不同的线程进行日志记录,因此 logcat 中的消息顺序可能会在应用程序运行之间发生变化并出现错误。
  • @Herrrmann,日志消息的顺序是一样的。在调试器中放置断点表明 onCancelled() 在 doInBackground() 返回结束之前被调用。

标签: android


【解决方案1】:

我可以确认(正如你们中的一些人已经说过的那样)有一个 bug in the Android source for 2.x versions 使得 onCancelled()cancel() 之后和 doInBackground() 完成之前被调用。

因此,如果您在 onCancelled() 中进行清理,您实际上会在 AsyncTask 运行的同时执行此操作,这将使您的应用程序崩溃!这让我们改变了设计……

希望对你有帮助!

【讨论】:

    【解决方案2】:

    是什么

    addUrlAsyncTask.cancel(true);
    

    返回?

    如果任务不能被中断,它将一直运行直到完成。

    doInBackgroundBody() 中是否有循环? IE。 doInBackground() 的以下实现将捕获调用 myTask.cancel(true) 时抛出的 InterruptedException,因此循环将继续进行,直到循环条件评估为 false。

            int count = 0;
            while(count++ < 10){
                try {
                    Log.d("MyAsyncTask", "WORKING doInBackground() is cancelled: " + this.isCancelled());
                    Thread.sleep(1000);
    
                } catch (Exception e) {
                    e.printStackTrace();
                    //break or return missing here to end the loop
                }
            }
    

    【讨论】:

    • @Hermann,cancel() 方法返回 true:07-10 16:24:03.743:VERBOSE/stopUpdates(4568):addUrlAsyncTask.cancel(true) 返回 true 是的,我里面有一个循环doInBackground() 方法。我还调用 isCancelled() 检查取消。 isCancelled() 方法返回 true。
    【解决方案3】:

    这似乎与我无法找到大量信息的错误有关。除了我有同样的问题。根据这个讨论:AsyncTask's cancel method - possible bug 这是 cancel() 代码中的竞争,应该在 post froyo 构建中修复。

    【讨论】:

    • 感谢您的提醒。我将玩一个 post froyo 构建,看看会发生什么。
    • 该死,对我来说它似乎仍然发生在 2.3 上。
    • 你是否使用中断异常来取消你的doInbackground函数?如果不是:我最终做的是在 AsyncTask 类中设置一个变量,并在我的 doInbackground 处理循环中检查它。然后在 postExecute 中,我可以通过检查该变量来区分已取消的任务或已完成的任务。
    • 除了调用 AsyncTask.abort() 之外,我还取消了任何正在进行的 HTTP 请求(这将导致异常)。我还检查了 AsyncTask 中的 isCancelled() 并且 isCancelled() 在取消发生的情况下返回 true,所以我实际上知道 AsyncTask 是否已被取消。只是 onCancelled() 方法的调用时机不是我预期的。不用担心,我根本不会打扰 onCancelled()。我似乎在这方面花费了过多的时间,我想我会改变我的设计。谢谢大家!
    猜你喜欢
    • 2014-08-19
    • 1970-01-01
    • 1970-01-01
    • 2016-07-31
    • 1970-01-01
    • 2015-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多