Android AsyncTask для длительных операций

Цитируя документацию по AsyncTask, найденную здесь, она гласит:

AsyncTasks в идеале следует использовать для коротких операций (максимум несколько секунд). Если вам нужно, чтобы потоки работали в течение длительного периода времени, настоятельно рекомендуется использовать различные API, предоставляемые пакетом java.util.concurrent, такие как Executor, ThreadPoolExecutor и FutureTask.

Теперь у меня возникает вопрос: почему? Функция doInBackground() запускается из потока пользовательского интерфейса, так какой же вред, если здесь выполняется длительная операция?

Ответ 1

Это очень хороший вопрос, для полного понимания проблемы требуется время как программист для Android. Действительно, у AsyncTask есть две основные проблемы:

  • Они плохо привязаны к жизненному циклу активности.
  • Они очень легко создают утечки памяти.

Внутри RoboSpice Мотивационное приложение (доступно в Google Play), мы подробно ответим на этот вопрос. Он даст подробное представление о AsyncTasks, Loaders, их функциях и недостатках, а также представит вам альтернативное решение для сетевых запросов: RoboSpice. Сетевые запросы являются обычным требованием для Android и по своей природе работают в течение длительного времени , Вот выдержка из приложения:

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

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

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

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

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

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

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


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

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

Ответ 2

почему?

Поскольку AsyncTask, по умолчанию использует пул потоков, который вы не создали. Никогда не связывайте ресурсы из пула, который вы не создали, так как вы не знаете, что такое требования к пулу. И никогда не связывайте ресурсы из пула, который вы не создали, если документация для этого пула говорит вам не об этом, как в данном случае.

В частности, начиная с Android 3.2 пул потоков, используемый AsyncTask по умолчанию (для приложений с android:targetSdkVersion, установленным в 13 или выше), имеет только один поток в нем - если вы связали этот поток неопределенно, ни одна из ваших других задач не будет запущена.

Ответ 3

Задача Aysnc - это специализированные потоки, которые все еще предназначены для использования с вашим графическим интерфейсом приложений, но сохраняя ресурсоемкие задачи потока пользовательского интерфейса. Поэтому, когда такие вещи, как обновления списков, изменение ваших представлений и т.д., Требуют выполнения некоторых операций выборки или операций обновления, вы должны использовать async-задачи, чтобы вы могли сохранить эти операции вне потока пользовательского интерфейса, но обратите внимание, что эти операции все еще связаны с пользовательским интерфейсом.

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

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

для получения дополнительной информации, см. темы:

AsyncTask для более чем нескольких секунд?

и

AsyncTask не остановится даже при уничтожении активности

Ответ 4

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

Решением этой проблемы является определение асинхронной задачи как статического внутреннего класса деятельности и использование слабой ссылки на контекст.

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