Подтвердить что ты не робот

Android AsyncTask не останавливается, когда отменяется, почему?

У меня есть 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() не влияет на состояние задачи? Я замечаю, что документы говорят, что метод отмены "попытается" остановить задачу, но при каких обстоятельствах это произойдет? Задача определенно работает, поскольку она выводит вывод журнала каждые десять секунд, и, как вы можете видеть выше, его статус возвращается как работающий.

Обновление. Я добавил трассировку, чтобы показать состояние isCancelled(), и это изменится. Таким образом, вызов cancel (true) меняет отмененное состояние с false на true, но, по-видимому, не влияет на состояние или останавливает поток.

4b9b3361

Ответ 1

Я углубился и вспомнил, что мой поток вызывал довольно плохо написанный метод, содержащий это, создавая другой поток внутри того, который мне нужно отменить:

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

Так что происходило то, что поток AsyncTask вызывает этот метод, чтобы подождать некоторое время, а во время сна вызов метода cancel() происходит в AsyncTask, что вызывает исключение в потоке sleep. Мой код бесполезно поймал и поглотил это исключение, вместо того, чтобы использовать его для закрытия AsyncTask.

Решение заключалось в том, чтобы искать исключение во сне, и если оно выбрано, чтобы спокойно выйти из потока. Приложение теперь работает так, как ожидалось, НО...

Состояние сразу после вызова метода cancel() остается RUNNING, но я подозреваю, что это происходит потому, что в этот момент он все еще работает, и ОС еще не отключила его. Я понятия не имею, правда ли это, но моя лучшая оценка.

Ответ 2

Имейте в виду, что ваша активность и ваша AsyncTask - это два отдельных потока. Поэтому, даже если вы отмените AsyncTask, код для отмены задачи может еще не запущен! Вот почему вы видите, что AsyncTask работает даже после исправления вашей ошибки. Я не думаю, что статус изменится, пока doInBackground() в вашей AsyncTask не завершится. (Поэтому убедитесь, что вы проверяете isCancelled() и возвращаетесь раньше, когда вас отменили!)

Ответ 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 в безопасном режиме way check this thread Как прервать поток быстрым и чистым способом в java?

Ответ 5

Еще одна возможная ошибка, чтобы проверить, запущена ли эта проблема:

Убедитесь, что вы не запускаете две AsyncTasks.