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

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

Embed Size (px)

DESCRIPTION

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

Citation preview

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

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

приложенияАлександр Османов

Android-разработчик, DataArt, Воронеж

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

Постановка задачи

• Часто во время работы приложения необходимо выполнять продолжительные задачи в фоне:– Выполнение HTTP запроса к серверу– Математический расчет

• После выполнения задачи необходимо уведомить UI о завершении, чтобы UI смог обновиться.

• Во время выполнения задачи может понадобиться узнать прогресс выполнения задачи

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

Почему нетривиально?

• Часто нужна возможность контроля над очередностью выполнения задач, возможность отмены и отслеживания прогресса выполнения

• Жизненный цикл визуальных компонентов часто ставит палки в колеса

• До сих пор нету официально рекомендованной Google организации взаимодействия с сервисом:– Broadcasts/Local broadcasts– Binding– ResultReceiver– createPendingResult

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

Как UI может узнать, что что-то происходит?

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

• Уведомления, реализованные в приложении — наши нестандартные уведомления, когда мы просто хотим отправить результат или прогресс выполнения фоновой задачи в UI.

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

AsyncTask?

• Самый очевидный и простой способ для новичка• Позволяет легко указывать, какой код исполнять в

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

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

AsyncTask

• Смешивание кода, посылающего HTTP запросы, с кодом, отвечающим за UI в вашей Activity

• Потеря контекста при пересоздании activity• Сложно контролировать очередность выполнения

запросов• Вы не можете управлять процессом, в котором будет

выполняться задача

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

Service!

• Специально созданный для такого рода задач компонент с независимым жизненным циклом

• Однако, требует дополнительной работы, чтобы организовать двустороннее общение с Activity

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

Наброски нашего фреймворка

• Command — каждая задача, которую мы хотим выполнять в фоне — отдельный класс-команда

• Command processor — сервис, отвечающий за планирование и выполнение команд

• ContentProvider — поможет реализовать хранение данных + управляемые обновления UI.

• Уведомления UI?

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

Broadcast

• После выполнения работы сервис посылает broadcast-сообщение с результатом работы

• UI получает сообщения при помощи BroadcastReceiver и ожидает входящих сообщений.

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

Broadcast

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

• Недостатки– Необходимо предпринять меры по защите сообщений, либо

установив разрешения, либо ограничив принимающие пакеты– Также сообщения потенциально могут быть присланы извне

другими приложениями. Опять необходимо предпринимать меры.– Проходит через системную очередь сообщений

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

LocalBroadcastManager

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

• Недостатки– Не могут работать между процессами

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

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 нашему сервису.

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

ResultReceiver

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

• Недостатки– Немного сложнее привязать к жизненному циклу Activity

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

Наброски нашего фреймворка

• Command — каждая задача, которую мы хотим выполнять в фоне — отдельный класс-команда

• Command processor — сервис, отвечающий за планирование и выполнение команд

• ContentProvider — поможет реализовать хранение данных + управляемые обновления UI.

• ResultReceiver — для возвращения результата работы фоновой задачи

• Реестр выполняющихся в данный момент операций

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

Command Processor

• Каждая задача, которую необходимо выполнить, будет инкапсулирована в класс-команду

• Каждая команда будет реализовывать Parcelable для более удобной передачи ее сервису

• Для каждой выполняемой команды будет создаваться уникальный идентификатор

• Команды образуют иерархию, где базовый класс инкапсулирует ResultReceiver и реализует общие методы, например, sendResult(int resultCode, Bundle data).

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

Command Processor

• В качестве процессора команд будет выступать Service– IntentService– Своя реализация сервиса с использованием ExecutorService

• Команды будут передаваться сервису в виде extras в Intent

• Сервис будет просто извлекать их и запускать в новом потоке (потоке из пула)

• Сервис также может хранить соответствие идентификатор-выполняемая команда для возможности реализации отмены команды

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

Command Processor

BaseCommand command = intent.getParcelableExtra(EXTRA_COMMAND);ResultReceiver callback = intent.getParcelableExtra(EXTRA_STATUS_RECEIVER);

command.execute(intent, context, callback);

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

Command Processor

ServiceExecutorService

Command 1

ResultReceiver

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

ServiceHelper

• ServiceHelper — это промежуточный слой между UI и сервисом, скрывающий рутину по созданию интентов сервису и предоставляющий нашему UI лишь набор бизнес методов для вызова.

• Также он координирует ответы от сервиса и содержит информацию о командах, выполняющихся в данный момент.

• ServiceHelper «живет» в Application scope приложения

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

ServiceHelper

• Дополнительные методы ServiceHelper– isExecuting(int requestId)– cancelCommand(int requestId)– addListener(ServiceCallbackListener listener)– removeListener(ServiceCallbackListener listener)

• Пример:– public int askServer(String question)

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

Принцип работы

• Activity вызывает бизнес-метод ServiceHelper• ServiceHelper генерирует и сохраняет ID запроса,

запоминает, что данная команда выполняется• Собирает Intent, в который вкладывет ResultReceiver,

экземпляр команды и отправляет сервису• Когда сервис завершает операцию, ServiceHelper

отвечает за то, чтобы все активные Activity получили результат

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

ServiceCallbackListener

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

• Это позволяет в реализациях Activity просто переопределить метод onServiceCallback и реализовать в нем логику аналогично тому, как это делается со стандартными callback-методами системы.

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

ServiceCallbackListener

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

не интерует конкретный запрос– resultCode, resultData – позволят обработать результат выполнения

команды

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

Принцип работы

Application

ServiceHelper

Service

Comand 1 Comand 2

Activity Listener

Provider

Receiver

Command

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

Отложенная проверка

• Имея ID запроса, мы можем выполнять отложенную проверку. Представим последовательность:– пользователь запустил действие, запустилась крутилка– закрыл приложение на 2 минуты– действие уже выполнилось– пользователь открыл снова

• тут мы проверяем в onResume, выполнилась ли операция, и убираем крутилку– т. е., просто вызываем getServiceHelper().isPending(requestId), если

нам это нужно.

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

Расширение №1. Отмена выполнения

• В базовый класс запрос добавим метод cancel()• Добавим метод cancelCommand(int commandId) в

ServiceHelper• Метод посылает Intent в сервис, который находит

команду по идентификатору и вызывает cancel()

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

Расширение №2. Прогресс операции

• Добавляем новый resultCode помимо SUCCESS и ERROR, и все.

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

Сторонние библиотеки, которые нам помогут

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

• Groundy – неплохая библиотека, реализующая command processor на основе генерации кода

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

В итоге мы получили

• Гибкую архитектуру для выполнения задач в фоне с поддержкой уведомлений UI

• Поддержка жизненного цикла Activity• Возможность легко вынести выполнение задач в отдельный

процесс, просто выставив атрибут сервису в манифесте• Возможность управлять стратегией выполнения задач меняя

реализацию сервиса (IntentService vs ExecutorService)• Расширяемость

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

Пример исходного кода

• Github - http://goo.gl/4voFM

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

Спасибо за внимание!

Вопросы?