1 / 31

Создание удобной архитектуры Android- приложения

Создание удобной архитектуры Android- приложения. Александр Османов Android- разработчик, DataArt , Воронеж. Постановка задачи. Часто во время работы приложения необходимо выполнять продолжительные задачи в фоне: Выполнение HTTP запроса к серверу Математический расчет

Télécharger la présentation

Создание удобной архитектуры Android- приложения

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Создание удобной архитектуры Android-приложения Александр Османов Android-разработчик, DataArt, Воронеж

  2. Постановка задачи • Часто во время работы приложениянеобходимо выполнять продолжительные задачи в фоне: • Выполнение HTTP запроса к серверу • Математический расчет • После выполнения задачи необходимо уведомить UI о завершении, чтобы UI смог обновиться. • Во время выполнения задачи может понадобиться узнать прогресс выполнения задачи

  3. Почему нетривиально? • Часто нужна возможность контроля над очередностью выполнения задач, возможность отмены и отслеживания прогресса выполнения • Жизненный цикл визуальных компонентов часто ставит палки в колеса • До сих пор нету официально рекомендованной Google организации взаимодействия с сервисом: • Broadcasts/Local broadcasts • Binding • ResultReceiver • createPendingResult

  4. Как UI может узнать, что что-то происходит? • «Управляемые» платформой — компоненты, реализующие ContentObserver. В случае использования приложением ContentProvider, а также адаптеров курсора подобные обновления достаются нам «бесплатно». О них речь не пойдет. • Уведомления, реализованные в приложении — наши нестандартные уведомления, когда мы просто хотим отправить результат или прогресс выполнения фоновой задачи в UI.

  5. AsyncTask? • Самый очевидный и простой способ для новичка • Позволяет легко указывать, какой код исполнять в фоновом потоке, какой в UI потоке • Позволяет публиковать прогресс операции • Код пишется легко и быстро

  6. AsyncTask • Смешивание кода, посылающего HTTP запросы, с кодом, отвечающим за UI в вашей Activity • Потеря контекста при пересоздании activity • Сложно контролировать очередность выполнения запросов • Вы не можете управлять процессом, в котором будет выполняться задача

  7. Service! • Специально созданный для такого рода задач компонент с независимым жизненным циклом • Однако, требует дополнительной работы, чтобы организовать двустороннее общение с Activity

  8. Наброски нашего фреймворка • Command — каждая задача, которую мы хотим выполнять в фоне — отдельный класс-команда • Command processor — сервис, отвечающий за планирование и выполнение команд • ContentProvider — поможет реализовать хранение данных + управляемые обновления UI. • Уведомления UI?

  9. Broadcast • После выполнения работы сервис посылает broadcast-сообщение с результатом работы • UI получает сообщения при помощи BroadcastReceiver и ожидает входящих сообщений.

  10. Broadcast • Преимущества • Легко использовать • Легко привязать к жизненному циклу Activity • Могут работать между процессами • Недостатки • Необходимо предпринять меры по защите сообщений, либо установив разрешения, либо ограничив принимающие пакеты • Также сообщения потенциально могут быть присланы извне другими приложениями. Опять необходимо предпринимать меры. • Проходит через системную очередь сообщений

  11. LocalBroadcastManager • Преимущества • Легко использовать • Легко привязать к жизненному циклу Activity • Не нужно думать о безопасности • Недостатки • Не могут работать между процессами

  12. ResultReceiver • Generic interface for receiving a callback result from someone. Use this by creating a subclass and implement onReceiveResult(int, Bundle), which you can then pass to others and send through IPC, and receive results they supply with send(int, Bundle). • Мы можем отправить экземпляр ResultReceiverпрямо как extra в Intent нашему сервису.

  13. ResultReceiver • Преимущества • Работает как локально, так и через процессы • Не нужно думать о безопасности • Недостатки • Немного сложнее привязать к жизненному циклу Activity

  14. Наброски нашего фреймворка • Command — каждая задача, которую мы хотим выполнять в фоне — отдельный класс-команда • Command processor — сервис, отвечающий за планирование и выполнение команд • ContentProvider — поможет реализовать хранение данных + управляемые обновления UI. • ResultReceiver — для возвращения результата работы фоновой задачи • Реестр выполняющихся в данный момент операций

  15. Command Processor • Каждая задача, которую необходимо выполнить, будет инкапсулирована в класс-команду • Каждая команда будет реализовывать Parcelable для более удобной передачи ее сервису • Для каждой выполняемой команды будет создаваться уникальный идентификатор • Команды образуют иерархию, где базовый класс инкапсулирует ResultReceiverи реализует общие методы, например, sendResult(intresultCode, Bundle data).

  16. Command Processor • В качестве процессора команд будет выступать Service • IntentService • Своя реализация сервиса с использованием ExecutorService • Команды будут передаваться сервису в виде extras в Intent • Сервис будет просто извлекать их и запускать в новом потоке (потоке из пула) • Сервис также может хранить соответствие идентификатор-выполняемая команда для возможности реализации отмены команды

  17. Command Processor BaseCommandcommand = intent.getParcelableExtra(EXTRA_COMMAND); ResultReceivercallback = intent.getParcelableExtra(EXTRA_STATUS_RECEIVER); command.execute(intent, context, callback);

  18. Command Processor ExecutorService Service Command 1 ResultReceiver

  19. ServiceHelper • ServiceHelper — это промежуточный слой между UI и сервисом, скрывающий рутину по созданию интентов сервису и предоставляющий нашему UI лишь набор бизнес методов для вызова. • Также он координирует ответы от сервиса и содержит информацию о командах, выполняющихся в данный момент. • ServiceHelper«живет» в Application scope приложения

  20. ServiceHelper • Дополнительные методы ServiceHelper • isExecuting(intrequestId) • cancelCommand(intrequestId) • addListener(ServiceCallbackListener listener) • removeListener(ServiceCallbackListener listener) • Пример: • public intaskServer(String question)

  21. Принцип работы • Activity вызывает бизнес-метод ServiceHelper • ServiceHelper генерирует и сохраняет ID запроса, запоминает, что данная команда выполняется • Собирает Intent, в который вкладывет ResultReceiver, экземпляр команды и отправляет сервису • Когда сервис завершает операцию, ServiceHelper отвечает за то, чтобы все активные Activity получили результат

  22. ServiceCallbackListener • Слушателем может быть что угодно. Для удобства я сделал базовый класс Activity, выступающий в роли слушателя и подписывающийся на обновления при запуске. • Это позволяет в реализациях Activity просто переопределить метод onServiceCallback и реализовать в нем логику аналогично тому, как это делается со стандартными callback-методами системы.

  23. ServiceCallbackListener • void onServiceResult(intrequestId, Intent intent,intresultCode, Bundle resultData); • requestIdпозволяет нам идентифицировать конкретный запрос • Intent позволит нам идентифицировать класс команды, если нас не интерует конкретный запрос • resultCode, resultData – позволят обработать результат выполнения команды

  24. Принцип работы Application Activity Listener ServiceHelper Receiver Command Service Provider Comand 1 Comand 2

  25. Отложенная проверка • Имея ID запроса, мы можем выполнять отложенную проверку. Представим последовательность: • пользователь запустил действие, запустилась крутилка • закрыл приложение на 2 минуты • действие уже выполнилось • пользователь открыл снова • тут мы проверяем в onResume, выполнилась ли операция, и убираем крутилку • т. е., просто вызываем getServiceHelper().isPending(requestId), если нам это нужно.

  26. Расширение №1. Отмена выполнения • В базовый класс запрос добавим метод cancel() • Добавим метод cancelCommand(intcommandId) в ServiceHelper • Метод посылает Intent в сервис, который находит команду по идентификатору и вызывает cancel()

  27. Расширение №2. Прогресс операции • Добавляем новый resultCodeпомимо SUCCESS и ERROR, и все.

  28. Сторонние библиотеки, которые нам помогут • Ottoот Square – очень удобная реализация event bus. В нашей схеме подойдет для передачирезультатов команды • Использует reflection • Работает только в одном процессе и одном потоке • Groundy – неплохая библиотека, реализующая command processor на основе генерации кода

  29. В итоге мы получили • Гибкую архитектуру для выполнения задач в фоне с поддержкой уведомлений UI • Поддержка жизненного цикла Activity • Возможность легко вынести выполнение задач в отдельный процесс, просто выставив атрибут сервису в манифесте • Возможность управлять стратегией выполнения задач меняя реализацию сервиса (IntentService vs ExecutorService) • Расширяемость

  30. Пример исходного кода • Github - http://goo.gl/4voFM

  31. Спасибо за внимание! Вопросы?

More Related