Я загружаю некоторые данные из Интернета в фоновом режиме (я использую AsyncTask
) и отображаю диалоговое окно прогресса во время загрузки. Ориентация меняется, действие перезапускается, и затем мой AsyncTask завершается - я хочу закрыть диалоговое окно progess и начать новое действие. Но вызов dismissDialog иногда вызывает исключение (возможно, потому что действие было уничтожено, а новое действие еще не было запущено).
Каков наилучший способ решения этой проблемы (обновление пользовательского интерфейса из фонового потока, которое работает, даже если пользователь меняет ориентацию)? Кто-то из Google предоставил какое-то "официальное решение"?
Ответы:
Шаг 1: Сделайте
AsyncTask
наstatic
вложенный класс, или совершенно отдельный класс, только не внутренний (не статический вложенный) класс.Шаг № 2:
AsyncTask
УдерживайтеActivity
элемент via с помощью элемента данных, задайте его с помощью конструктора и установщика.Шаг № 3: При создании
AsyncTask
, поставьте токActivity
конструктору.Шаг № 4: В
onRetainNonConfigurationInstance()
, вернитеAsyncTask
, после отсоединения его от первоначальной, теперь уходящей деятельности.Шаг № 5:
onCreate()
ЕслиgetLastNonConfigurationInstance()
нетnull
, приведите его к своемуAsyncTask
классу и вызовите своего сеттера, чтобы связать вашу новую деятельность с задачей.Шаг № 6: Не ссылаться на член данных деятельности из
doInBackground()
.Если вы будете следовать приведенному выше рецепту, все будет работать.
onProgressUpdate()
иonPostExecute()
приостановлены между началомonRetainNonConfigurationInstance()
и концом последующегоonCreate()
.Вот пример проекта, демонстрирующего технику.
Другой подход состоит в том, чтобы бросить
AsyncTask
и переместить свою работу вIntentService
. Это особенно полезно, если выполняемая работа может быть длительной и продолжаться независимо от действий пользователя (например, загрузка большого файла). Вы можете использовать упорядоченную трансляцию,Intent
чтобы действие реагировало на выполняемую работу (если оно все еще находится на переднем плане), или поднимало,Notification
чтобы сообщить пользователю, была ли работа выполнена. Вот сообщение в блоге с большим количеством об этом образце.источник
onRetainNonConfigurationInstance()
устарела и предлагает использовать альтернативуsetRetainInstance()
, но она не возвращает объект. Можно ли справитьсяasyncTask
с изменением конфигурации с помощьюsetRetainInstance()
?Fragment
УДЕРЖИВАЙТЕAsyncTask
. ИмеютFragment
вызовsetRetainInstance(true)
на себя. ИметьAsyncTask
только поговорить сFragment
. Теперь, при изменении конфигурации,Fragment
он не уничтожается и не воссоздается (даже при наличии действия), и поэтомуAsyncTask
он сохраняется при изменении конфигурации.Принятый ответ был очень полезен, но в нем нет диалогового окна прогресса.
К счастью для вас, читатель, я создал чрезвычайно полный и работающий пример AsyncTask с диалоговым окном прогресса !
источник
Я трудился целую неделю, чтобы найти решение этой дилеммы, не прибегая к редактированию файла манифеста. Предположения для этого решения:
Реализация
Вам нужно будет скопировать два файла, найденные внизу этого поста, в ваше рабочее пространство. Просто убедитесь, что:
Все ваши
Activity
s должны расширятьсяBaseActivity
В
onCreate()
,super.onCreate()
должна вызываться после инициализации любых членов , которые нужно получить доступ к вашимASyncTask
с. Кроме того, переопределите,getContentViewId()
чтобы предоставить идентификатор макета формы.Переопределите,
onCreateDialog()
как обычно, для создания диалогов, управляемых действием.Посмотрите код ниже для примера статического внутреннего класса, чтобы сделать ваши AsyncTasks. Вы можете сохранить свой результат в mResult для доступа позже.
И наконец, чтобы запустить новое задание:
Это оно! Я надеюсь, что это надежное решение поможет кому-то.
BaseActivity.java (организуйте импорт самостоятельно)
SuperAsyncTask.java
источник
Да.
Решение - это скорее предложение архитектуры приложения, а не просто код .
Они предложили 3 шаблона проектирования, которые позволяют приложению работать синхронно с сервером, независимо от состояния приложения (оно будет работать, даже если пользователь завершает приложение, пользователь меняет экран, приложение закрывается, любое другое возможное состояние, где операция фоновых данных может быть прервана, это покрывает это)
Это предложение объясняется в выступлении клиентских приложений REST для Android во время ввода-вывода Google 2010 Вирджилом Добянским. Это 1 час, но это очень стоит посмотреть.
Основой этого является абстрагирование сетевых операций от объекта,
Service
который работает независимо от любогоActivity
в приложении. Если вы работаете с базами данных, использованиеContentResolver
иCursor
даст вам готовый шаблон Observer, который будет удобен для обновления пользовательского интерфейса без какой-либо дополнительной логики, как только вы обновите свою локальную базу данных с извлеченными удаленными данными. Любой другой код после операции будет выполняться с помощью обратного вызова, переданного (для этогоService
я используюResultReceiver
подкласс).Во всяком случае, мое объяснение на самом деле довольно расплывчато, вы должны обязательно посмотреть речь.
источник
Хотя ответ Марка (CommonsWare) действительно работает для изменения ориентации, он терпит неудачу, если действие уничтожается напрямую (как в случае телефонного звонка).
Вы можете обрабатывать изменения ориентации И редкие уничтоженные события Activity, используя объект Application для ссылки на ASyncTask.
Там отличное объяснение проблемы и решения здесь :
Кредит полностью идет на Райана для выяснения этого.
источник
Через 4 года Google решил проблему, просто вызвав setRetainInstance (true) в Activity onCreate. Это сохранит ваш экземпляр активности во время ротации устройства. У меня также есть простое решение для старых Android.
источник
Вы должны вызывать все действия активности, используя обработчик активности. Так что, если вы в какой-то теме, вы должны создать Runnable и опубликовать его с помощью обработчика Activitie. В противном случае ваше приложение будет зависать иногда с фатальным исключением.
источник
Это мое решение: https://github.com/Gotchamoh/Android-AsyncTask-ProgressDialog
В основном шаги:
onSaveInstanceState
чтобы сохранить задачу, если она еще обрабатывается.onCreate
I получить задание , если оно было сохранено.onPause
I отбрасывать ,ProgressDialog
если это показано.onResume
I показать ,ProgressDialog
если задача все еще обрабатывается.источник