AsyncTask дольше, чем несколько секунд?

Ссылка на API указывает,

AsyncTasks идеально подходит для коротких операций (всего несколько секунд).

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

Я считаю, что AyncTasks, как правило, все еще привязаны к стеку операций переднего плана, который породил их, так что, например, если Activity выдает AsyncTask, пользователь покидает приложение, а затем ОС не хватает памяти, он убьет процесс Activity ( Включая все еще запущенную AsyncTask), и просто ожидайте, что вы восстановите состояние и начнете, если пользователь возобновит / вернет ваше приложение.

Для более длительных задач, в частности, в том случае, когда их будет только один или несколько, вам, скорее всего, понадобится Служба, потому что они могут сохраняться даже тогда, когда пользовательский интерфейс вашего приложения отключается, чтобы сохранить память.

Отказ от ответственности: я не сделал кодировку Android некоторое время, поэтому этот ответ может быть устаревшим или основан на некорректном понимании того, как все работает. Я удалю это предостережение, если кто-то с более недавним опытом может прокомментировать, чтобы подтвердить; Высокопоставленные люди могут просто отредактировать этот абзац, если они знают, что это правильно.

Ответ, данный @Walter Mundt, верен. Тем не менее, я хотел бы добавить дополнение к информации и указать указатель на библиотеку, которая может использоваться для длительной работы AsyncTask.

AsyncTasks разработаны для работы в фоновом режиме. И да, это правильно, если ваша AsyncTask длится две длинные, тогда вы столкнетесь с двумя разными проблемами:

  1. Деятельности плохо привязаны к жизненному циклу активности, и вы не получите результат своей AsyncTask, если ваша деятельность умрет. Действительно, да, вы можете, но это будет грубый путь.
  2. AsyncTask не очень хорошо документированы. Наивная, хотя и интуитивно понятная, реализация и использование асинтезы может быстро привести к утечкам памяти.

RoboSpice , библиотека, которую я хотел бы представить, как это предлагает @Walter Mundt, использует фоновый сервис для выполнения таких запросов. Он был разработан для сетевых запросов (потенциально длительный по своей природе), но он может быть легко адаптирован для выполнения только длительных задач, не связанных с сетью. Я был бы рад добавить к нему патч.

Вот почему AsyncTasks вредны для длительных задач. Следующей причиной является адаптация к мотивам мотиваций RoboSpice : приложение, объясняющее, почему использование RoboSpice заполняет потребность на платформе Android.

Жизненный цикл AsyncTask и Activity

AsyncTasks не соответствуют жизненному циклу экземпляров действий. Если вы запустите AsyncTask внутри Activity и вы повернете устройство, действие будет уничтожено и будет создан новый экземпляр. Но AsyncTask не умрет. Он будет продолжаться до тех пор, пока он не завершится.

И когда он завершится, AsyncTask не будет обновлять пользовательский интерфейс нового действия. Действительно, он обновляет прежний экземпляр активности, которая больше не отображается. Это может привести к исключению типа java.lang.IllegalArgumentException: View не подключен к оконному менеджеру, если вы используете, например, findViewById для получения представления внутри Activity.

Проблема с утечкой памяти

Очень удобно создавать AsyncTasks как внутренние классы вашей деятельности. Поскольку AsyncTask должен будет манипулировать представлениями Activity, когда задача завершена или выполняется, использование внутреннего класса Activity кажется удобным: внутренние классы могут напрямую обращаться к любому полю внешнего класса.

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

В долгосрочной перспективе это приводит к утечке памяти: если AsyncTask длится долго, он сохраняет активность «живым», в то время как Android хочет избавиться от нее, поскольку она больше не может отображаться. Активность не может быть собрана мусором, и это центральный механизм для Android, чтобы сохранить ресурсы на устройстве.

Прогресс вашей задачи будет потерян

Вы можете использовать некоторые обходные пути для создания длительной асинтезы и управлять ее жизненным циклом в соответствии с жизненным циклом деятельности. Вы можете либо отменить AsyncTask в методе onStop своей деятельности, либо вы можете завершить свою задачу async, а не потерять ее прогресс и перевести ее в следующий экземпляр своей деятельности .

Это возможно, и мы показываем, как в мотивах RobopSpice, но он становится сложным и код не является общим. Более того, вы все равно потеряете ход своей задачи, если пользователь покинет деятельность и вернется. Эта же проблема возникает с Loaders, хотя это будет более простой эквивалент AsyncTask с повторным обходным решением, упомянутым выше.

Использование службы Android

Лучшим вариантом является использование службы для выполнения ваших длинных фоновых задач. И это именно то решение, которое предлагает RoboSpice. Опять же, он предназначен для сетей, но может быть распространен на не связанные с сетью вещи. Эта библиотека имеет большое количество функций .

Вы можете получить представление об этом менее чем за 30 секунд благодаря инфографике .


На самом деле очень плохая идея использовать AsyncTasks для длительных операций. Тем не менее, они подходят для коротких живых, таких как обновление вида через 1 или 2 секунды.

Я рекомендую вам загрузить приложение RoboSpice Motivations , оно действительно объясняет это в глубину и предоставляет образцы и демонстрации различных способов выполнения некоторых фоновых операций.


Если вы ищете альтернативу RoboSpice для не связанных с сетью задач (например, без кеширования), вы также можете взглянуть на ленту .