简体   繁体   English

Android AsyncTask在取消时不会停止,为什么?

[英]Android AsyncTask won't stop when cancelled, why?

I've an AsyncTask that I shut down in the Activity's onPause lifecycle event, so it doesn't run when someone leaves the app, but it keeps going despite this. 我在Activity的onPause生命周期事件中关闭了一个AsyncTask,因此当有人离开应用程序时它不会运行,但它会继续运行,尽管如此。 I added some tracing and this snippet shows the problem. 我添加了一些跟踪,这个片段显示了问题。

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

Outputs: 输出:

Task state: RUNNING
Task state: RUNNING

Why is the cancel() method not having any effect on the state of the task? 为什么cancel()方法对任务的状态没有任何影响? I notice the docs say the cancel method will "attempt" to stop the task, but under what circumstances will it fail? 我注意到文档说取消方法将“尝试”停止任务,但在什么情况下会失败? The task is definitely running as it is outputting log output every ten seconds, and as you can see above its status is returned as running. 该任务肯定正在运行,因为它每十秒输出一次日志输出,如上所示,其状态将返回为运行状态。

Update: I added tracing to show me the isCancelled() state as well and that DOES change. 更新:我添加了跟踪以显示isCancelled()状态,并且会更改。 So the call to cancel(true) is changing the cancelled state from false to true, but apparently having no effect on the Status, or stopping the thread. 所以取消(true)的调用是将取消状态从false更改为true,但显然对Status没有影响,或者停止线程。

Keep in mind that your Activity and your AsyncTask are two separate threads. 请记住,您的Activity和AsyncTask是两个独立的线程。 So even if you cancel the AsyncTask, the code to cancel the task may not run yet! 因此,即使取消AsyncTask,取消任务的代码也可能无法运行! That's why you are seeing the AsyncTask still running even after fixing your bug. 这就是为什么即使在修复bug之后你仍然看到AsyncTask仍在运行的原因。 I don't think the status will change until doInBackground() in your AsyncTask has completed. 在AsyncTask中的doInBackground()完成之前,我认为状态不会改变。 (So make sure you're checking isCancelled() and returning early when you've been cancelled!) (因此,请确保您正在检查isCancelled()并在取消时提前返回!)

thread.cancel(true);

Only sets a variable in the AsyncTask class. 仅在AsyncTask类中设置变量。 What you need to do is implement a loop into your background task if you haven't already. 你需要做的是在你的后台任务中实现一个循环,如果你还没有。 Then check and break the loop if cancel is true for each iteration. 然后检查并中断循环,如果每次迭代取消为真。

@Override  
protected Void doInBackground(Void... params) {  

    synchronized(this) {

        for(int i = 0; i < 9000; i++) {

            if(thread.isCancelled()) break;

            // do stuff

        }

    }

}

Then just set it to cancelled whenever you need it to stop. 然后只需将其设置为取消,只要您需要它停止。 It will then stop before the following iteration. 然后它将在下一次迭代之前停止。

@Override
public void onStop() {

    super.onStop();

    thread.cancel(true);

}

@Override
public void onDestroy() {

    super.onDestroy();

    thread.cancel(true);

}

I dug deeper and remembered that my thread was calling a rather badly written method containing this, producing another thread inside the one I need to cancel: 我深入挖掘并记住我的线程正在调用包含此内容的写得很差的方法,在我需要取消的内部生成另一个线程:

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

So what was happening was that the AsyncTask thread calls this method to wait a while, and during the sleep the cancel() method call occurs on the AsyncTask, which causes an exception in the thread sleep. 所以发生的事情是AsyncTask线程调用此方法等待一段时间,并且在睡眠期间,在AsyncTask上发生cancel()方法调用,这会导致线程休眠中出现异常。 My code unhelpfully caught and absorbed that exception, instead of using it to shut down the AsyncTask. 我的代码无益地捕获并吸收了该异常,而不是使用它来关闭AsyncTask。

The solution was to look for an exception on the sleep, and if it is thrown, to quietly exit the thread. 解决方案是在睡眠中寻找异常,如果它被抛出,则静静地退出线程。 The app now works as expected, BUT... 该应用程序现在按预期工作,但...

The status immediately after the cancel() method call remains RUNNING, but I suspect this is because at that moment it is still running, and the OS has not yet shut it down. cancel()方法调用之后的状态仍然是RUNNING,但我怀疑这是因为此时它仍然在运行,并且操作系统尚未将其关闭。 I have no idea if that's true, but that's my best estimate. 我不知道这是不是真的,但那是我最好的估计。

Another possible pitfall to check if you're running into this problem: 另一个可能的缺陷是检查您是否遇到此问题:

Make sure you are not starting two AsyncTasks. 确保您没有启动两个AsyncTasks。

Even if you know how cancel works it's very hard to determine in what state your thread will be stopped. 即使您知道取消是如何工作的,也很难确定您的线程将在什么状态下停止。 So I suggest to implement your own safe way to stop your thread, so you'll be sure in what state you are stopping and you be sure there are no memory leaks, etc. From more info how to stop a thread in java in safe way check this thread How to abort a thread in a fast and clean way in java? 所以我建议你实现自己的安全方法来阻止你的线程,这样你就可以确定你停止了什么状态,你确定没有内存泄漏等等。从更多信息如何在java中停止一个线程安全检查这个线程如何在java中快速,干净地中止线程?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM