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

Ссылочные ссылки API,

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

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

Ответ 1

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

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

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

Ответ 2

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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


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