Подтвердить что ты не робот

Особенности проектирования Android: AsyncTask vs Service (IntentService?)

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

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

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

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

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

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

4b9b3361

Ответ 1

По-моему, это самая сложная/сложная часть основного/среднего развития Android. Например, на BlackBerry это время проще.

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

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

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

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

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

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

Ответ 2

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

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

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

То, что меня больше всего волнует, - это то, что приложение займет 10-20 минут в первый раз, я бы сказал, что Пользователь будет временно изменять задачи или устанавливать телефон до завершения (что может вызывают все те же осложнения, если телефон спит). Учитывая это соображение, ваш лучший выбор может быть связан с вашей деятельностью, связанной с потоками. Чтобы защитить ваш пользовательский интерфейс, я бы сделал диалоговое окно "Прогресс" для вашей деятельности, которое получает ваши обратные вызовы. Это ограничивает ввод пользователя в ваше приложение и позволяет вашему сервису продолжать то, что ему нужно. Затем переопределите Activity onResume, чтобы проверить статус вашего Сервиса и если он запущен. Затем вы можете reset Диалог немедленно.

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

Ответ 3

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

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

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

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

Ответ 4

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

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

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

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

Ответ 5

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

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

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

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

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

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

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