Вопросы проектирования Android: AsyncTask vs Service (IntentService?) - PullRequest
52 голосов
/ 29 сентября 2010

Я разрабатываю приложение для Android, которое должно выполнить следующие шаги:

  1. пользователь нажимает кнопку или иным образом указывает на «синхронизацию данных».
  2. процесс синхронизации будетиспользуйте веб-сервисы REST для перемещения данных на сервер и с него.
  3. данные будут храниться локально в базе данных sqlite.
  4. процесс синхронизации должен предоставлять обновления статуса / сообщения для пользовательского интерфейса
  5. пользователю не должно быть позволено переходить к другим частям приложения и выполнять больше работы во время процесса синхронизации.

При первом запуске процесса синхронизации может потребоваться 10-20 минут.После начальной синхронизации меньше данных будет передано и сохранено, и я ожидаю, что процесс займет 1-2 минуты или меньше.

Я много читал о Android 101 * * и различных примерахиспользуя Сервис ... Но я не совсем понимаю конструктивные соображения и компромиссы при выборе одного дизайна над другим.В настоящее время мой демо-проект заглушен с помощью AsyncTask.После просмотра (большей части) разработки клиентских приложений REST для Android: http://code.google.com/events/io/2010/sessions/developing-RESTful-android-apps.html# Я растерялся, описанные здесь шаблоны проектирования кажутся слишком сложными, возможно, потому, что я просто "еще не понял".

Я пришел из Java, Spring, веб-приложений и приложений для настольных компьютеров.Мышление и проектирование с точки зрения портативного устройства для меня совершенно новое.(Что происходит при изменении макета экрана? Что происходит, когда телефон звонит, когда я запускаю синхронизацию?) Если сделать 2 шага назад, если начальная синхронизация будет таким длительным процессом, есть ли лучший способ для этого?мне подумать о проблеме -> решение, пользовательский опыт, пользовательские ожидания от приложения, работающего на телефоне?

Хотелось бы услышать мнение более опытных разработчиков Android, которые уже боролись с этими вопросами.

Ответы [ 5 ]

44 голосов
/ 14 ноября 2010

На мой взгляд, это самая сложная / сложная часть основной / средней разработки для Android. Например, на BlackBerry это ВРЕМЕНИ проще.

Определенно вам нужно использовать Service.

AsyncTask не подходит, потому что он тесно «привязан» к вашему Activity с помощью ручки Context (иначе вы не сможете обновить пользовательский интерфейс Activity с вашего AsyncTask). Однако Activity может быть убит ОС, если Activity ушел в фоновом режиме. Примером причины перехода в фоновый режим может быть входящий звонок - пользователь переключается на приложение «Телефон», поэтому ваш Activity становится невидимым. В этом случае (в зависимости от текущего состояния ОЗУ) ОС может решить убить одно из фоновых (невидимых для пользователя) действий.

Некоторые разработчики обходят это, устраивая статические вещи для выполнения длительных действий внутри. Некоторые рекомендуют использовать Application экземпляр. Это потому, что статический материал и Application существуют, пока существует весь процесс приложения. Однако это неправильные обходные пути. Процессы в Android также могут быть убиты, когда ОС решит, что пора. ОС Android имеет свои соображения о том, что она может убить и в каком порядке. Все процессы разделены на 5 уровней «убиваемости». Вот документ , где указаны эти уровни. Интересно там почитать:

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

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

Кроме того, вы, скорее всего, захотите использовать NotificationManager для уведомления пользователя о вашем продолжительном завершении действия (или неудаче), если ваш Activity в настоящее время невидим. Вот NotificationManager info для начала.

12 голосов
/ 09 ноября 2010

Есть несколько соображений, которые вы должны взвесить, чтобы лучше решить, как подходить к вашей ситуации.Похоже, вам нужно хорошее сравнение между двумя подходами ... Итак, вот список сходств, а также различий и дополнительных соображений, которые необходимо учитывать при работе на портативном устройстве.

Службачасть вашего приложения, которая не имеет пользовательского интерфейса.Он может быть вызван пользовательским интерфейсом (Activity) для запуска или может быть запущен любым другим компонентом вашего Приложения.При разработке у вас есть свобода размещать его в другом потоке или даже запускать в другой задаче или процессе.Это позволяет в конечном итоге отделить его от вашего пользовательского интерфейса.Кроме того, вы можете запустить Службу для запуска самостоятельно (startService) или привязать к ней свою деятельность (bindService) в зависимости от ваших потребностей.Используя пользовательские обработчики, вы можете установить обратные вызовы для обновления пользовательского интерфейса с вашим прогрессом.Служба не обязательно завершается, если Пользователь изменяет Операции, но может быть завершена в ЛЮБОЕ время ОС.

AsyncTask всегда создается из потока пользовательского интерфейса.Он допускает только определенные обратные вызовы, но упрощает процесс многопоточности для целей относительно коротких транзакций (по сравнению с выделенными отдельными многопоточными службами), которые по своей природе связаны с действиями, выполняемыми действием.Всякий раз, когда пользователь меняет активность, AsyncTask ставится на «паузу» и может даже умереть, потому что больше нет потока пользовательского интерфейса для вашей активности.

Больше всего меня беспокоит, если приложениеесли в первый раз это займет 10–20 минут, я предположу, что пользователь либо временно поменяет задачи, либо выключит телефон до его завершения (что может вызвать все те же осложнения, если телефон спит).Учитывая это соображение, многопоточный сервис, связанный с вашей деятельностью, может быть вашим лучшим выбором.Чтобы защитить ваш пользовательский интерфейс, я бы сделал диалог прогресса для вашей активности, который получает ваши обратные вызовы прогресса.Это ограничивает пользовательский ввод в ВАШЕМ приложении и позволяет вашему сервису продолжать работать так, как ему нужно.Затем переопределите Activity onResume, чтобы проверить состояние вашей службы и работает ли она.Затем вы можете немедленно сбросить диалог.

Учитывая, что это мой предпочтительный метод, я бы также принял во внимание, что ОС в любом случае может убить приложение.Поэтому убедитесь, что у вас есть какой-то способ обнаружить неполную или частичную синхронизацию.Затем вы можете возобновить работу автоматически после перезапуска вашей активности или службы.

5 голосов
/ 29 сентября 2010

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

Google Sync запускается как служба в фоновом режиме, поскольку синхронизация может занять некоторое время.Возможно, вам придется следовать их пути и создать свой собственный сервис синхронизации, с которым вы можете общаться.Вот некоторые мысли о том, как этого добиться:

http://mylifewithandroid.blogspot.com/2008/01/about-binders.html

Вы можете определенно общаться между Сервисом и Деятельностью, но это сложно сделать правильно.

3 голосов
/ 26 февраля 2013

Выбор в основном зависит от дизайна приложения. Поскольку AsyncTask и IntentService стоят на своем, то, что вам может понадобиться в приложении (взаимодействие с пользователем), более важно, а затем выберите одно или оба. Некоторые сценарии упомянуты ниже (в основном то, что я испытал при разработке приложений)

  • Предположим, что приложения имеют каналы каналов - где выполняется несколько вызовов API, чтобы сделать страницу презентабельной (/ getFriends, / getDates, / getPictures и т. Д.), Вы можете деформировать все такие вызовы API в один AsyncTask с помощью executor, который является многопоточным, и последовательность выполнения не имеет значения. В отличие от IntentService, который последовательно выполняет все вызовы в одном рабочем потоке. Для высокопроизводительного устройства с многоядерным вызовом AsyncTask более эффективен. И если вы запустите AsyncTask в потоке пользовательского интерфейса, то обновление IU будет очень просто (читайте меньше кода котельной пластины). И даже если пользователь покидает страницу, при умном использовании, не держась за контекст, приложение не падает.

  • Предполагается, что вы пытаетесь написать приложение, которое не требует, чтобы пользователь был в представлении / активности / фрагменте, и общее время выполнения, чтобы показать что-то, не является критически важным (предположим, служба синхронизации или уведомление пользователя / сигнал тревоги пользователя) ) тогда IntentService - лучший выбор. (нет проблем с запуском Asynctask в потоке пользовательского интерфейса, так что вам не нужно писать обработчик для принудительного внесения изменений в пользовательский интерфейс и т. д. и т. д. и меньше кода котельной пластины)

Из моего опыта - напишите небольшое приложение для обоих и сравните плюсы и минусы, чтобы получить лучшее представление. (p.s я бы посоветовал взглянуть на приложение iosched от google, чтобы получить лучшую идею - они используют Asynctask и IntentService)

2 голосов
/ 14 сентября 2014

Я предпочитаю комбинировать IntentService + BroadcastReceiver, потому что они дают вам действительно сильный уровень контроля

Вы обязательно должны убедиться, что пользовательский интерфейс работает, если вы обновляете что-то на экране. Сообщалось, что сбои ASyncTask были одной из главных причин сбоев Android. Этого можно избежать, сохраняя какую-то переменную «activityIsAlive» и пропуская или задерживая обновление пользовательского интерфейса, если действие не работает.

Комбинация IntentService + BroadcastReceiver немного более устойчива к сбою, так как в большинстве учебных пособий вы должны отключить BroadcastReceiver onPause или onStop. Если вы этого не сделаете, вам снова придется отключить обновление интерфейса. Где-то есть команда runOnUiThread, которая поможет вам обновлять пользовательский интерфейс.

Комбинация IntentService + BroadcastReceiver также более расширяема. Вы можете создавать функции и расширять BroadcastReceiver, чтобы сделать более элегантное решение для обработки REST. Тем не менее, он требует больше сантехники против ASyncTask

Если вы задержите обновление пользовательского интерфейса, вы сможете установить его на OnWindowFocusChangedListener. Когда эта функция получает значение true, это означает, что пользовательский интерфейс активен.

tldr; Убедитесь, что активность и / или фрагмент активен, прежде чем обновлять пользовательский интерфейс, если вы работаете в фоновом режиме

2015 Редактировать: проверить Loaders также. Немного сложнее понять, потому что за кулисами происходит много всего

...