【问题标题】:Android AsyncTask won't stop when cancelled, why?Android AsyncTask 取消时不会停止,为什么?
【发布时间】:2011-02-10 16:14:01
【问题描述】:

我有一个在 Activity 的 onPause 生命周期事件中关闭的 AsyncTask,因此当有人离开应用程序时它不会运行,但尽管如此,它仍会继续运行。我添加了一些跟踪,这个 sn-p 显示了问题。

    Trace.d(TAG,"Task state: " + myTask.getStatus() );
    myTask.cancel(true);
    Trace.d(TAG,"Task state: " + myTask.getStatus() );

输出:

Task state: RUNNING
Task state: RUNNING

为什么 cancel() 方法对任务的状态没有任何影响?我注意到文档说取消方法将“尝试”停止任务,但在什么情况下会失败?该任务肯定正在运行,因为它每十秒输出一次日志输出,并且如您所见,它的状态返回为正在运行。

更新:我添加了跟踪以向我显示 isCancelled() 状态,并且该状态确实发生了变化。所以对 cancel(true) 的调用将取消状态从 false 更改为 true,但显然对状态没有影响,或者停止线程。

【问题讨论】:

  • 有没有办法让任务内部的循环检查任务是否被取消,然后简单地退出循环?
  • cancel的返回值是多少?它告诉你它确实取消了它吗?
  • @Joel 是的,我可以这样做,但是当我在其他地方使用 cancel() 方法时,我想了解它为什么没有达到我的预期
  • @Mayra cancel() 方法返回true,表示任务已被取消——这不是真的,任务在调用cancel后每十秒继续给出日志输出。
  • 我敢肯定,不害怕深入研究资源的人(我是!)可以找到答案。只有当finish() 被调用时,状态才会设置为FINISHED,这发生在FutureTask 使用的内部处理程序中。 cancel()isCancelled() 实际上是在该 FutureTask 成员上调用的。如果该任务被取消,则调用 onCancelled()。可以用于测试吗?来源:google.com/codesearch/p?hl=en#uX1GffpyOZk/core/java/android/os/…

标签: android android-asynctask


【解决方案1】:

请记住,您的 Activity 和 AsyncTask 是两个独立的线程。所以即使你取消了 AsyncTask,取消任务的代码可能还没有运行!这就是为什么即使在修复错误之后您仍然看到 AsyncTask 仍在运行的原因。我认为在您的 AsyncTask 中的 doInBackground() 完成之前,状态不会改变。 (所以请确保您查看isCancelled() 并在您被取消后尽早返回!)

【讨论】:

    【解决方案2】:

    我深入挖掘并记得我的线程正在调用一个包含它的写得很糟糕的方法,在我需要取消的线程中产生另一个线程:

    public static void haveASleep(int milliseconds)
    {
        try
        {
            Thread.sleep(milliseconds);
        }
        catch (InterruptedException ie)
        {
            Trace.w(TAG,"Sleep interrupted");
        }
    }
    

    所以发生的事情是 AsyncTask 线程调用该方法等待一段时间,而在睡眠期间,AsyncTask 上发生了 cancel() 方法调用,这导致线程睡眠异常。我的代码毫无帮助地捕获并吸收了该异常,而不是使用它来关闭 AsyncTask。

    解决方法是在睡眠中寻找异常,如果抛出异常,则安静地退出线程。该应用程序现在可以按预期运行,但是...

    cancel() 方法调用后的状态仍然是 RUNNING,但我怀疑这是因为此时它仍在运行,并且操作系统尚未将其关闭。我不知道这是否属实,但这是我的最佳估计。

    【讨论】:

      【解决方案3】:
      thread.cancel(true);
      

      只在 AsyncTask 类中设置一个变量。如果您还没有,您需要做的是在您的后台任务中实现一个循环。然后检查并在每次迭代的取消为真时中断循环。

      @Override  
      protected Void doInBackground(Void... params) {  
      
          synchronized(this) {
      
              for(int i = 0; i < 9000; i++) {
      
                  if(thread.isCancelled()) break;
      
                  // do stuff
      
              }
      
          }
      
      }
      

      然后,只要您需要它停止,只需将其设置为取消即可。然后它将在下一次迭代之前停止。

      @Override
      public void onStop() {
      
          super.onStop();
      
          thread.cancel(true);
      
      }
      
      @Override
      public void onDestroy() {
      
          super.onDestroy();
      
          thread.cancel(true);
      
      }
      

      【讨论】:

        【解决方案4】:

        即使您知道取消是如何工作的,也很难确定您的线程将在什么状态下停止。所以我建议实施你自己的安全方式来停止你的线程,这样你就可以确定你在什么状态下停止并且你确定没有内存泄漏等。从更多信息如何在安全的情况下停止 java 中的线程方法检查这个线程How to abort a thread in a fast and clean way in java?

        【讨论】:

        • 我正在使用 AsyncTask,它是一个围绕 Java 线程处理的 Android 包装器,至少在理论上可以轻松启动、管理和停止线程。目前我怀疑我最终将不得不蛮力停止线程,但我想了解为什么 cancel() 方法没有按照它的设计意图执行。
        • AsyncTask 不仅仅是一个 Android 包装器。它相对于 Java 线程的主要优点是您可以使用在 UI 线程中执行的方法轻松地从它更新您的 gui。所以 AsyncTask 与 Java 线程有同样的停止问题。
        【解决方案5】:

        检查您是否遇到此问题的另一个可能的陷阱:

        确保您没有启动两个 AsyncTask。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-09-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多