Скачать презентацию
Идет загрузка презентации. Пожалуйста, подождите
Презентация была опубликована 10 лет назад пользователемЮрий Эрастов
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(int resultCode, Bundle data).
16 Command Processor В качестве процессора команд будет выступать Service –IntentService –Своя реализация сервиса с использованием ExecutorService Команды будут передаваться сервису в виде extras в Intent Сервис будет просто извлекать их и запускать в новом потоке (потоке из пула) Сервис также может хранить соответствие идентификатор- выполняемая команда для возможности реализации отмены команды
17 Command Processor BaseCommand command = intent.getParcelableExtra(EXTRA_COMMAND); ResultReceiver callback = intent.getParcelableExtra(EXTRA_STATUS_RECEIVER); command.execute(intent, context, callback);
18 Command Processor Service ExecutorService Command 1 ResultReceiver
19 ServiceHelper ServiceHelper это промежуточный слой между UI и сервисом, скрывающий рутину по созданию интентов сервису и предоставляющий нашему UI лишь набор бизнес методов для вызова. Также он координирует ответы от сервиса и содержит информацию о командах, выполняющихся в данный момент. ServiceHelper «живет» в Application scope приложения
20 ServiceHelper Дополнительные методы ServiceHelper –isExecuting(int requestId) –cancelCommand(int requestId) –addListener(ServiceCallbackListener listener) –removeListener(ServiceCallbackListener listener) Пример: –public int askServer(String question)
21 Принцип работы Activity вызывает бизнес-метод ServiceHelper ServiceHelper генерирует и сохраняет ID запроса, запоминает, что данная команда выполняется Собирает Intent, в который вкладывет ResultReceiver, экземпляр команды и отправляет сервису Когда сервис завершает операцию, ServiceHelper отвечает за то, чтобы все активные Activity получили результат
22 ServiceCallbackListener Слушателем может быть что угодно. Для удобства я сделал базовый класс Activity, выступающий в роли слушателя и подписывающийся на обновления при запуске. Это позволяет в реализациях Activity просто переопределить метод onServiceCallback и реализовать в нем логику аналогично тому, как это делается со стандартными callback-методами системы.
23 ServiceCallbackListener void onServiceResult(int requestId, Intent intent, int resultCode, Bundle resultData); –requestId позволяет нам идентифицировать конкретный запрос –Intent позволит нам идентифицировать класс команды, если нас не интерует конкретный запрос –resultCode, resultData – позволят обработать результат выполнения команды
24 Принцип работы Application ServiceHelper Service Comand 1Comand 2 ActivityListener Provider Receiver Command
25 Отложенная проверка Имея ID запроса, мы можем выполнять отложенную проверку. Представим последовательность: –пользователь запустил действие, запустилась крутилка –закрыл приложение на 2 минуты –действие уже выполнилось –пользователь открыл снова тут мы проверяем в onResume, выполнилась ли операция, и убираем крутилку –т. е., просто вызываем getServiceHelper().isPending(requestId), если нам это нужно.
26 Расширение 1. Отмена выполнения В базовый класс запрос добавим метод cancel() Добавим метод cancelCommand(int commandId) в ServiceHelper Метод посылает Intent в сервис, который находит команду по идентификатору и вызывает cancel()
27 Расширение 2. Прогресс операции Добавляем новый resultCode помимо SUCCESS и ERROR, и все.
28 Сторонние библиотеки, которые нам помогут Otto от Square – очень удобная реализация event bus. В нашей схеме подойдет для передачи результатов командыOtto –Использует reflection –Работает только в одном процессе и одном потоке Groundy – неплохая библиотека, реализующая command processor на основе генерации кодаGroundy
29 В итоге мы получили Гибкую архитектуру для выполнения задач в фоне с поддержкой уведомлений UI Поддержка жизненного цикла Activity Возможность легко вынести выполнение задач в отдельный процесс, просто выставив атрибут сервису в манифесте Возможность управлять стратегией выполнения задач меняя реализацию сервиса (IntentService vs ExecutorService) Расширяемость
30 Пример исходного кода Github -
31 Спасибо за внимание! Вопросы?
Еще похожие презентации в нашем архиве:
© 2024 MyShared Inc.
All rights reserved.