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

У меня есть AsyncTask, который я отключил в событии жизненного цикла onPause Activity, поэтому он не запускается, когда кто-то покидает приложение, но, несмотря на это, продолжает работать. Я добавил трассировку, и этот фрагмент показывает проблему.

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

Выходы:

Task state: RUNNING
Task state: RUNNING

Почему метод отмены() никак не влияет на состояние задачи? Я заметил, что в документах говорится, что метод отмены «попытается» остановить задачу, но при каких обстоятельствах это не удастся? Задача определенно выполняется, так как она выводит вывод журнала каждые десять секунд, и, как вы можете видеть выше, ее статус возвращается как работающий.

Обновление: я добавил трассировку, чтобы показать мне состояние isCancelled(), и это ДЕЙСТВИТЕЛЬНО меняется. Таким образом, вызов cancel(true) изменяет состояние отмены с false на true, но, по-видимому, не влияет на состояние или останавливает поток.


person Ollie C    schedule 10.02.2011    source источник
comment
Есть ли способ для цикла внутри вашей задачи проверить, была ли задача отменена, и просто выйти из цикла?   -  person Joel Mueller    schedule 10.02.2011
comment
Каково возвращаемое значение от отмены? Он сказал вам, что отменил его?   -  person Cheryl Simon    schedule 10.02.2011
comment
@Joel Да, я могу это сделать, но, поскольку я использую метод отмены () в других местах, я хочу понять, почему он не делает то, что я от него ожидаю.   -  person Ollie C    schedule 10.02.2011
comment
@Mayra Метод отмены () возвращает значение true, указывая на то, что задача БЫЛА отменена — это неверно, задача продолжает выводить журнал каждые десять секунд после вызова отмены.   -  person Ollie C    schedule 10.02.2011
comment
Я уверен, что тот, кто не боится углубляться в источники (я!), может найти ответ. Статус устанавливается в FINISHED только тогда, когда вызывается finish(), и это происходит во внутреннем обработчике, используемом FutureTask. cancel() и isCancelled() на самом деле вызываются для этого FutureTask члена. Если эта задача отменена, вызывается onCancelled(). Можно ли это использовать для тестов? источники: google. com/codesearch/p?hl=en#uX1GffpyOZk/core/java/android/os/   -  person bigstones    schedule 10.02.2011


Ответы (5)


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

person idbrii    schedule 14.07.2011

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

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

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

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

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

person Ollie C    schedule 10.02.2011

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);

}
person tpbapp    schedule 24.12.2013

Даже если вы знаете, как работает отмена, очень сложно определить, в каком состоянии ваш поток будет остановлен. Поэтому я предлагаю реализовать свой собственный безопасный способ остановить поток, чтобы вы были уверены, в каком состоянии вы останавливаетесь, и были уверены, что нет утечек памяти и т. д. Из дополнительной информации о том, как остановить поток в java в безопасном как проверить этот поток Как прервать поток быстрым и чистым способом в java?

person Mojo Risin    schedule 10.02.2011
comment
Я использую AsyncTask, который представляет собой оболочку Android для обработки потоков Java, чтобы, по крайней мере теоретически, упростить запуск, управление и остановку потоков. На данный момент я подозреваю, что в конечном итоге мне придется остановить поток методом грубой силы, но я хочу понять, почему метод cancel() не делает того, для чего он, по-видимому, был разработан. - person Ollie C; 10.02.2011
comment
AsyncTask — это не просто оболочка для Android. Его основное преимущество перед потоком Java заключается в том, что вы можете легко обновлять свой графический интерфейс с помощью методов, которые выполняются в потоке пользовательского интерфейса. Таким образом, AsyncTask имеет ту же проблему с остановкой, что и поток Java. - person Mojo Risin; 11.02.2011

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

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

person blub    schedule 09.10.2013