Ответ от @Romain Guy правильный. Тем не менее, я хотел бы добавить дополнение информации и дать указатель на библиотеку или 2, которые можно использовать для длительной работы AsyncTask и даже больше для асинхронных задач, ориентированных на сеть.
AsyncTasks были разработаны для работы в фоновом режиме. И да, вы можете остановить это, используя метод cancel
. Когда вы загружаете материал из Интернета, я настоятельно рекомендую вам позаботиться о вашей ветке, когда она находится в состоянии блокировки ввода-вывода . Вы должны организовать загрузку следующим образом:
public void download() {
//get the InputStream from HttpUrlConnection or any other
//network related stuff
while( inputStream.read(buffer) != -1 && !Thread.interrupted() ) {
//copy data to your destination, a file for instance
}
//close the stream and other resources
}
Использование флага Thread.interrupted
поможет вашему потоку правильно выйти из блокирующего состояния io. Ваш поток будет более отзывчив на вызов метода cancel
.
Ошибка проектирования AsyncTask
Но если ваша AsyncTask длится слишком долго, вы столкнетесь с 2 различными проблемами:
- Действия плохо привязаны к жизненному циклу активности, и вы не получите результат своей AsyncTask, если ваша активность умрет. В самом деле, да, вы можете, но это будет трудный путь.
- AsyncTask не очень хорошо задокументированы. Наивная, хотя и интуитивно понятная реализация и использование асинхронной задачи может быстро привести к утечкам памяти.
RoboSpice , библиотека, которую я хотел бы представить, использует фоновый сервис для выполнения такого рода запросов. Он был разработан для сетевых запросов. Предоставляет дополнительные функции, такие как автоматическое кэширование результатов запросов.
Вот причина, по которой AsyncTasks вредны для долго выполняющихся задач. Следующее обоснование - это адаптация отрывков из мотиваций RoboSpice : приложение, которое объясняет, почему использование RoboSpice удовлетворяет потребность на платформе Android.
Жизненный цикл AsyncTask и Activity
AsyncTasks не соответствуют жизненному циклу экземпляров Activity. Если вы запускаете AsyncTask внутри Activity и вращаете устройство, Activity будет уничтожена и будет создан новый экземпляр. Но AsyncTask не умрет. Он будет жить до тех пор, пока не завершится.
И когда он завершится, AsyncTask не будет обновлять пользовательский интерфейс новой активности. Действительно, он обновляет прежний экземпляр действия, которое
больше не отображается. Это может привести к исключению типа java.lang.IllegalArgumentException: представление не привязано к оконному менеджеру, если вы
используйте, например, findViewById, чтобы получить представление внутри Activity.
Проблема утечки памяти
Очень удобно создавать AsyncTasks как внутренние классы вашей Деятельности. Поскольку AsyncTask нужно будет манипулировать представлениями
действия, когда задача завершена или выполняется, использование внутреннего класса действия кажется удобным: внутренние классы могут
прямой доступ к любому полю внешнего класса.
Тем не менее, это означает, что внутренний класс будет содержать невидимую ссылку на свой экземпляр внешнего класса: Activity.
В долгосрочной перспективе это приводит к утечке памяти: если AsyncTask длится долго, он сохраняет активность «живой»
тогда как Android хотел бы избавиться от него, так как он больше не может отображаться. Деятельность не может быть сборкой мусора, и это центральная
механизм для Android для сохранения ресурсов на устройстве.
Прогресс вашей задачи будет потерян
Вы можете использовать некоторые обходные пути для создания длительной асинхронной задачи и управления ее жизненным циклом в соответствии с жизненным циклом действия. Вы можете либо отменить AsyncTask в методе onStop своей активности , либо позволить завершить асинхронную задачу, не теряя ее прогресс и связать ее со следующим экземпляром вашей активности .
Это возможно, и мы покажем, как в RobopSpice мотивация, но она усложняется и код на самом деле не является универсальным. Более того, вы все равно потеряете выполнение своей задачи, если пользователь покинет действие и вернется. Эта же проблема возникает с загрузчиками, хотя это будет более простой эквивалент AsyncTask с повторным решением проблемы, упомянутым выше.
Использование службы Android
Лучшим вариантом является использование службы для выполнения ваших долгосрочных фоновых задач. И это именно то решение, которое предлагает RoboSpice. Опять же, он предназначен для работы в сети, но может быть распространен на не связанные с сетью вещи. Эта библиотека имеет большое количество функций .
Вы даже можете получить представление об этом менее чем за 30 секунд благодаря инфографике .
Это действительно очень и очень плохая идея использовать AsyncTasks для длительных операций. Тем не менее, они хороши для кратковременных, таких как обновление просмотра через 1 или 2 секунды.
Я рекомендую вам загрузить приложение RoboSpice Motivations , оно действительно подробно объясняет это и предоставляет примеры и демонстрации различных способов выполнения некоторых связанных с сетью вещей.
Если вы ищете альтернативу RoboSpice для задач, не связанных с сетью (например, без кэширования), вы также можете взглянуть на Tape .