安卓异步任务在被取消后仍然不停止,为什么?

16

我有一个AsyncTask,我在Activity的onPause生命周期事件中关闭它,以便当有人离开应用程序时它不再运行,但是它仍然持续进行。 我添加了一些跟踪,以下代码片段显示了问题。

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

输出:

Task state: RUNNING
Task state: RUNNING
为什么cancel()方法对任务的状态没有任何影响?我注意到文档中说cancel方法将“尝试”停止任务,但在什么情况下会失败?这个任务肯定正在运行,因为它每十秒输出一次日志,并且正如你上面看到的那样,它的状态被返回为running。
更新:我添加了跟踪代码以显示isCancelled()的状态,而它的状态确实发生了改变。所以调用cancel(true)将取消状态从false更改为true,但显然对状态或线程的停止没有任何影响。

你的任务中的循环是否有一种方法可以检查任务是否已被取消,并简单地退出循环? - Joel Mueller
取消操作的返回值是什么?它告诉你它已经被取消了吗? - Cheryl Simon
@Joel 是的,我可以做到,但是由于我在其他地方使用了 cancel() 方法,因此我想了解为什么它没有按照我的期望进行。 - Ollie C
@Mayra cancel()方法返回true,表示任务已被取消 - 但事实并非如此,任务在调用cancel()方法后仍然每十秒输出日志。 - Ollie C
我相信那些不害怕深入源代码的人(我就是其中之一!)可以找到答案。只有在finish()被调用时,状态才会被设置为“FINISHED”,而这发生在由FutureTask使用的内部处理程序中。 cancel()isCancelled()实际上是在该FutureTask成员上调用的。如果该任务被取消,则会调用onCancelled()。这能用于测试吗?来源:http://www.google.com/codesearch/p?hl=en#uX1GffpyOZk/core/java/android/os/AsyncTask.java&d=3 - bigstones
5个回答

3

请记住,您的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,但我怀疑这是因为此时它仍在运行,操作系统尚未关闭它。我不知道这是否正确,但这是我最好的估计。

2
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

        }

    }

}

只需在需要停止时将其设置为"cancelled",它将在下一次迭代之前停止。

@Override
public void onStop() {

    super.onStop();

    thread.cancel(true);

}

@Override
public void onDestroy() {

    super.onDestroy();

    thread.cancel(true);

}

0
即使您知道如何取消操作,确定线程将被停止的状态仍然非常困难。因此,我建议您实现自己安全的线程停止方式,以确保您停止线程的状态,并确保没有内存泄漏等问题。如需了解更多有关Java中如何以安全的方式停止线程的信息,请查看以下主题How to abort a thread in a fast and clean way in java?

我正在使用AsyncTask,它是Android封装Java线程处理的一种方式,理论上至少可以使启动、管理和停止线程变得容易。目前我怀疑最终将不得不强制停止线程,但我想了解为什么cancel()方法没有执行它设计的功能。 - Ollie C
AsyncTask不仅仅是Android的包装器。它相对于Java线程的主要优势在于,您可以使用在UI线程中执行的方法轻松地从中更新GUI。因此,AsyncTask与Java线程一样存在停止问题。 - Mojo Risin

0

如果你遇到这个问题,另一个可能的陷阱是要检查一下:

确保你没有启动两个AsyncTasks。


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