AsyncTask
Отличная вещь для запуска сложных задач в другом потоке.
Но когда происходит изменение ориентации или другое изменение конфигурации во время AsyncTask
работы, ток Activity
уничтожается и перезапускается. И когда экземпляр AsyncTask
связан с этим действием, он завершается неудачно и вызывает окно сообщения «принудительное закрытие».
Итак, я ищу какую-то «лучшую практику», чтобы избежать этих ошибок и предотвратить сбой AsyncTask.
То, что я видел до сих пор:
- Отключите изменения ориентации. (Конечно, не так, как вы должны это делать.)
- Позволить задаче выжить и обновить ее новым экземпляром действия через
onRetainNonConfigurationInstance
- Просто отмените задачу, когда
Activity
объект уничтожен, и перезапустите его, когда объектActivity
будет создан снова. - Связывание задачи с классом приложения вместо экземпляра действия.
- Какой-то метод, используемый в проекте "shelves" (через onRestoreInstanceState)
Некоторые примеры кода:
Android AsyncTasks во время поворота экрана, часть I и часть II
Можете ли вы помочь мне найти лучший подход, который наилучшим образом решает проблему и также прост в реализации? Сам код также важен, так как я не знаю, как решить это правильно.
android
multithreading
exception
каркать
источник
источник
Ответы:
Как НЕ использовать
android:configChanges
для решения этой проблемы. Это очень плохая практика.Как НЕ использовать
Activity#onRetainNonConfigurationInstance()
либо. Это менее модульный и не очень подходящий дляFragment
приложений на основе.Вы можете прочитать мою статью, описывающую, как обрабатывать изменения конфигурации, используя сохраненные
Fragment
s. Это решает проблему сохраненияAsyncTask
изменения поворота поперек. Вы в основном нужно для размещенияAsyncTask
внутриFragment
, вызовsetRetainInstance(true)
наFragment
, и сообщить оAsyncTask
«s прогресса / результаты обратно этоActivity
через стопорноеFragment
.источник
TabActivity
. Честно говоря, я не уверен, почему мы даже говорим об этом ... все согласныFragment
с тем, что это путь. :)Обычно я решаю эту проблему, когда мои AsyncTasks запускают Intents в обратном вызове .onPostExecute (), чтобы они не модифицировали Activity, которая их запускала напрямую. Действия слушают эти трансляции с динамическими BroadcastReceivers и действуют соответственно.
Таким образом, AsyncTasks не нужно заботиться о конкретном экземпляре Activity, который обрабатывает их результат. Они просто «кричат», когда они закончили, и если в это время активность (активная и сфокусированная / находится в возобновленном состоянии), которая заинтересована в результатах задачи, она будет обработана.
Это включает в себя немного больше накладных расходов, поскольку среда выполнения должна обрабатывать трансляцию, но я обычно не против. Я думаю, что использование LocalBroadcastManager вместо общесистемной системы по умолчанию немного ускоряет процесс.
источник
Вот еще один пример AsyncTask, который использует
Fragment
для обработки изменений конфигурации во время выполнения (например, когда пользователь поворачивает экран)setRetainInstance(true)
. Определенный (регулярно обновляемый) индикатор выполнения также демонстрируется.Этот пример частично основан на официальных документах « Сохранение объекта во время изменения конфигурации» .
В этом примере работа, требующая фонового потока, заключается в простой загрузке изображения из Интернета в пользовательский интерфейс.
Алекс Локвуд, по-видимому, прав в том, что когда дело доходит до обработки изменений конфигурации во время выполнения с помощью AsyncTasks, использование «сохраненного фрагмента» является наилучшей практикой.
onRetainNonConfigurationInstance()
осуждается в Lint, в Android Studio. Официальные документы предупреждают нас, используяandroid:configChanges
, от Обработки Изменения Собственности , ...Тогда возникает вопрос, следует ли вообще использовать AsyncTask для фонового потока.
Официальная ссылка на AsyncTask предупреждает ...
В качестве альтернативы можно использовать службу, загрузчик (используя CursorLoader или AsyncTaskLoader) или поставщика содержимого для выполнения асинхронных операций.
Я делю остальную часть поста на:
Процедура
Начните с базовой AsyncTask как внутреннего класса действия (это не обязательно должен быть внутренний класс, но, вероятно, будет удобно). На этом этапе AsyncTask не обрабатывает изменения конфигурации во время выполнения.
Добавьте вложенный класс RetainedFragment, который расширяет класс Fragement и не имеет собственного пользовательского интерфейса. Добавьте setRetainInstance (true) к событию onCreate этого фрагмента. Предоставьте процедуры для установки и получения ваших данных.
В onCreate () внешнего класса Activity обрабатывает RetainedFragment: ссылается на него, если он уже существует (в случае, если Activity перезапускается); создать и добавить его, если он не существует; Затем, если он уже существует, получите данные из RetainedFragment и установите свой интерфейс с этими данными.
Инициируйте AsyncTask из пользовательского интерфейса
Добавьте и закодируйте определенный индикатор выполнения:
Весь код для вышеуказанной процедуры
План мероприятий.
Задание с: внутренним классом AsyncTask; вложенный класс RetainedFragment, который обрабатывает изменения конфигурации во время выполнения (например, когда пользователь поворачивает экран); и определенное обновление индикатора на регулярной основе. ...
В этом примере библиотечная функция (на которую ссылается выше с явным префиксом пакета com.example.standardapplibrary.android.Network) выполняет настоящую работу ...
Добавьте любые разрешения, необходимые для фоновой задачи, в файл AndroidManifest.xml ...
Добавьте свою активность в AndroidManifest.xml ...
источник
Недавно я нашел хорошее решение здесь . Он основан на сохранении объекта задачи через RetainConfiguration. На мой взгляд, решение очень элегантное, и я начал его использовать. Вам нужно просто вложить свою асинктаску из базовой задачи, и все.
источник
Основываясь на ответе @Alex Lockwood и ответах @William & @quickdraw mcgraw на этот пост: Как обрабатывать сообщения обработчика, когда действие / фрагмент приостановлен , я написал общее решение.
Таким образом, ротация обрабатывается, и если действие переходит в фоновый режим во время выполнения асинхронной задачи, действие получит обратные вызовы (onPreExecute, onProgressUpdate, onPostExecute & onCancelled) после возобновления, поэтому никакое IllegalStateException не будет выброшено (см. Как обрабатывать обработчик). сообщения, когда активность / фрагмент приостановлен ).
Было бы здорово иметь такие же, но с общими типами аргументов, такими как AsyncTask (например, AsyncTaskFragment <Params, Progress, Result>), но мне не удалось это сделать быстро и у меня нет времени в данный момент. Если кто-то хочет сделать улучшение, пожалуйста, не стесняйтесь!
Код:
Вам понадобится PauseHandler:
Пример использования:
источник
Вы можете использовать Loaders для этого. Проверьте Док здесь
источник
Для тех, кто хочет уклоняться от фрагментов, вы можете оставить AsyncTask, работающий на изменениях ориентации, с помощью onRetainCustomNonConfigurationInstance () и некоторой проводки.
(Обратите внимание, что этот метод является альтернативой устаревшему onRetainNonConfigurationInstance () ).
Похоже, что это решение не часто упоминается, хотя. Я написал простой пример для иллюстрации.
Ура!
источник
Я реализовал библиотеку, которая может решить проблемы с приостановкой активности и восстановлением во время выполнения вашей задачи.
Вы должны реализовать
AsmykPleaseWaitTask
иAsmykBasicPleaseWaitActivity
. Ваша деятельность и фоновые задачи будут работать нормально, даже если вы будете поворачивать экран и переключаться между приложениямиисточник
БЫСТРАЯ РАБОТА (не рекомендуется)
Чтобы избежать действия, которое нужно уничтожить и создать самостоятельно, нужно объявить свою деятельность в файле манифеста: android: configChanges = "direction | keyboardHidden | screenSize
Как уже упоминалось в документах
источник