- Взаимодействие RESTful-сервиса с Spring for Android
- Что вы создадите
- Что вам потребуется
- Создание Android-проекта
- Создание Android Manifest
- Создание строковых ресурсов
- Создание разметки
- Создание меню
- Создание класса представления
- Добавление зависимостей
- Создание activity
- Запуск клиента
- RESTful API под Android: pattern B
- Краткое описание паттернов и обзор
- Приложение FinchVideo
- Выводы
Взаимодействие RESTful-сервиса с Spring for Android
Этот урок освещает процесс создания приложения, которое использует Spring For Android RestTemplate для взаимодействия с MVC RESTful web-сервисом.
Что вы создадите
Вы создадите Android-клиент, который взаимодействует с Spring RESTful web-сервисом. В частности, клиент будет взаимодействовать с сервисом, созданным в уроке Создание RESTful Web-сервиса.
Android-клиент будет доступен через Android эмулятор и будет взаимодействовать с сервисом через запрос на:
Сервис будет отвечать JSON сообщением:
Android-клиент будет отображать ID и содержимое в форме.
Что вам потребуется
- Примерно 15 минут свободного времени
- Android Studio
- Интернет соединение
Создание Android-проекта
Создайте в Android Studio новый проект. Если хотите, можете использовать проект из каталога initial и перейти к шагу Создание класса представления. Когда вы закончите, то сможете сравнить ваш код с кодом из каталога complete и запустить клиент. Используйте «Rest» для приложения и имен модуля, а также измените имя пакета на «org.hello.rest». Укажите местоположение вашего проекта и оставьте остальные параметры как есть по умолчанию.
Следующий скрин отображает некоторые параметры для настройки иконок приложения. Оставьте как есть по умолчанию.
Следующий скрин отображает параметры для выбора типа используемого activity. Выберите «Blank Activity».
Последний скрин отображает некоторые каталоги для настроек activity, разметки и имени фрагмента. И снова оставьте как есть настройки по умолчанию и нажмите кнопку «Finish».
Когда вы создадите проект, вы увидите, что добавлены несколько файлов.
Для прохождения этого урока, вам предстоит отредактировать следующие файлы:
- Rest/src/main/AndroidManifest.xml
- Rest/src/main/res/values/strings.xml
- Rest/src/main/res/layout/fragment_main.xml
- Rest/src/main/res/menu/main.xml
- Rest/build.gradle
- Rest/src/main/java/org/hello/rest/MainActivity.java
Создание Android Manifest
После того, как вы создали проект, AndroidManifest.xml был также создан в базовом исполнении. Android Manifest содержит всю необходимую информацию для запуска Android-приложения и не может быть собрано без него. Манифест также содержит любые разрешения, которые приложение запрашивает у операционной системы Android. В нашем случае, приложению необходим доступ к интернет для создания HTTP запросов.
Добавьте INTERNET разрешение, чтобы приложение могло получить доступ к ресурсам через интернет.
Создание строковых ресурсов
Текстовые строки могут ссылаться на файловые ресурсы как из приложения, так и на другие источники. В этом уроке изпользуются четыре текстовых представления и пункт меню, где каждый из этих UI элементов нуждается в тектовом описании. Для начала, удалите строки hello_world и action_settings . Они не используются в этом учебном материале, поэтому могут быть удалены. Затем добавьте строки id_label , id_value , content_label , content_value и action_refresh для каждого UI виджета на будущее.
Создание разметки
Файл разметки является местом, где вы определяете визуальную структуру пользовательсткого интерфейса вашего приложения. Когда вы создали проект, Android Studio добавило фрагмент разметки. Как следует из названия, фрагмент разметки представляет собой часть общей разметки. В нашем случае, фрагмент разметки использован для отображения некоторого текста в главном activity. Удалите существующий «Hello world» TextView , который был добавлен автоматически изначально при создании проекта. Затем измените фрагмент разметки, включив в него четыре TextView виджета.
Разметка включает некоторую информацию о расположении и размере виджетов. Android Studio отображает визуальное представление разметки в окне предварительного просмотра:
Создание меню
Проект содержит меню для главного activity с существующим пунктом «Settings». Удалите этот пункт и добавьте пункт «Refresh». Обратите внимание, что для значения пункта меню также используется строковый ресурс.
Android Studio отображает визуальное представление разметки в окне предварительного просмотра:
Создание класса представления
По медели JSON данных, полученных из RESTful HTTP запроса, вам необходимо создать класс представления, который определяет поля. Перейдите в «org.hello.rest» пакет из панели Project. Выберите «New. » из меню «File».
Выберите «Java Class»
Добавьте переменные id и content , а также их методы получения(getters).
Добавление зависимостей
Чтобы использовать Spring for Android RestTemplate , вам необходимо добавить соответсвующие Maven зависимости в файл сборки Gradle. RestTemplate позволяет использовать Jackson, мощный JSON обработчик для Java.
Создание activity
Шаблон проектирования Model-View-Controller(MVC) широко используется в Android приложениях. Activity управляет представлением, которое является разметкой, уже созданной вами. Когда вы создали проект, MainActivity было создано с реализацией по умолчанию. Измените его, чтобы совершать RESTful HTTP запросы и обновлять представление. Каждое изменение пояснено ниже.
Для начала, добавьте частный класс HttpRequestTask . Этот класс наследуется от AsyncTask , который представляет собой механизм Android для выполнения потенциальных, долговременных действий вне главного UI потока. Это очень важно, т.к. иначе вы бы заблокировали UI, вынуждая пользователя поверить в то, что приложение не отвечает или завершилось с ошибкой.
Spring предоставляет шаблонный класс RestTemplate . Он позволяет взаимодействовать с большинством RESTful сервисами. В методе doInBackground класса HttpRequestTask , RestTemplate использован для создания HTTP запроса и разбора JSON ответа в Greeting объект. Когда doInBackground заканчивается, вызывается метод onPostExecute , в котором текстовые значения виджетов greetingIdText и greetingContentText обновляются результатом HTTP запроса.
Далее, добавьте метод onStart с вызовом метода execute класса HttpRequestTask . Метод onStart является частью жизненного цикла Activity и вызывается при запуске activity. В результате, HTTP запрос выполнится, когда приложение загружается.
Напоследок, обновите метод onOptionsItemSelected , чтобы также выполнять HTTP запрос, когда пункт меню «Refresh» выбран. Это позволяет вам совершать дополнительные HTTP запросы без необходимости закрывать и перезапускать приложение.
Запуск клиента
Теперь вы можете запустить приложение из Android Studio. Для этого нажмите кнопку проигрывателя(зеленый треугольник) на панели инструментов Android Studio. Перед вами откроется диалоговое окно с выбором устройства, на котором будет запущено приложение. У вас должно быть Android-устройство, либо эмулятор, настроенный для запуска приложения. Если у вас нет настроенного Android Virtual Device (AVD), то вы можете выбрать кружочек для создания нового.
После выбора устройства, Android Studio соберет и развернет приложение:
ID значение будет увеличиваться каждый раз при нажатии кнопки обновления в меню.
Поздравляем! Вы только что разработали простой REST-клиент, используя Spring for Android.
Источник
RESTful API под Android: pattern B
Совсем недавно, на собеседовании в Яндексе, мне довелось обсуждать организацию Rest-взаимодействия в Android-приложениях. В ходе обсуждения всплыл вопрос – почему из трех паттернов, предложенных на Google IO 2010 Virgil Dobjanschi, первый используется существенно чаще двух других. Вопрос меня заинтересовал.
Поскольку тема обсуждения достаточно узкоспециализированная, я с позволения читателей пропущу слова о том, насколько правильная архитектура Rest-взаимодействия важна в Android-приложениях и как часто Android-разработчики сталкиваются с подобными задачами.
Краткое описание паттернов и обзор
(подробнее)
Pattern A | Pattern B | Pattern C |
Используется Service API: Activity -> Service -> Content Provider. В данном варианте Activity работает с API Android Servcie. При необходимости послать REST-запрос Activity создает Service, Service асинхронно посылает запросы к REST-серверу и сохраняет результаты в Content Provider (sqlite). Activity получает уведомление о готовности данных и считывает результаты из Content Provider (sqlite). | Используется ContentProvider API: Activity -> Content Provider -> Service. В этом случае Activity работает с API Content Provider, который выступает фасадом для сервиса. Данный подход основан на схожести Content Provider API и REST API: GET REST эквивалентен select-запросу к базе данных, POST REST эквивалентен insert, PUT REST update, DELETE REST delete. Результаты Activity так же загружает из sqlite. | Используется Content Provider API + SyncAdapter: Activity -> Content Provider -> Sync Adapter. Вариация подхода «B», в котором вместо сервиса используется собственный Sync Adapter. Activity дает команду Content Provider, который переадресовывает ее в Sync Adapter. Sync Adapter вызывается из Sync Manager, но не сразу, а в «удобный» для системы момент. Т.е. возможны задержки в исполнении команд. |
Беглый обзор подтвердил, что Pattern A используется действительно гораздо шире. Dv в своей замечательной статье «REST под Android. Часть 1: паттерны Virgil Dobjanschi» упоминает целый ряд библиотек и примеров реализации Pattern A (есть такой и на хабре), и всего один пример Pattern B – описание в книге «Programming Android, 2nd Edition» by Zigurd Mednieks, Laird Dornin, G. Blake Meike and Masumi Nakamura [1], в главе 13 «A Content Provider as a Facade for a RESTful Web Service», реализация есть на github.com. Других мне найти не удалось.
Чтение оригинала доклада Virgil Dobjanschi только добавило интриги.
Please note that in this particular pattern we broke the Content Provider contract a little bit. … Again, we’re not forcing you to adopt these particular design patterns.
В общем, не хотите – не используйте. Это воодушевляет.
Предлагаю кратко рассмотреть существующую реализацию Pattern B и попытаться понять, в чём же заключаются его особенности.
Приложение FinchVideo
Сразу отмечу, что этот код писался уважаемым G. Blake Meike в 2012 году, и с тех пор существенно не модифицировался, поэтому мы отнесёмся с пониманием к использованию всяких deprecated конструкций типа managedQuery, неиспользованию таких замечательных вещей как Loader, synchronized (HashMap) вместо ConcurrentHashMap и прочего – на архитектуру приложения они никак не влияют.
Итак, начнём с пользовательского интерфейса. В FinchVideoActivity всё вполне прозрачно – к ListView через SimpleCursorAdapter привязывается Cursor, в который и сливаются результаты запросов managedQuery к FinchVideoContentProvider.
Дальше – интереснее.
и HashMap — mRequestsInProgress (соответственно, набор выполняемых запросов). Обрабатываются результаты запросов в YouTubeHandler implements ResponseHandler, который и передаётся в задачу UriRequestTask при её создании.
Сопоставим существующие классы со схемой Pattern B.
С Activity и Content Provider всё достаточно ясно. Объект Service в явном виде в примере не используется, его функции и частично функции ServiceHelper по структурированию и запуску запросов выполняет FinchVideoContentProvider. Он же выполняет функции Processor, про Rest method написано выше. Такая вот упрощённая реализация.
Выводы
На основе анализа существующей реализации Pattern B и её описания, я сделал для себя следующие выводы
- Самый большой плюс Pattern B, как и описывает автор примера в разделе «Summary of Benefits» [1 — стр. 369] – увеличенная производительность запросов, поскольку они в первую очередь осуществляются к локальной БД (Content Provider);
- Обратная сторона этого плюса – рассогласование локальной и серверной БД и усложнённая логика получения данных.
Неудивительно, что автор примера использовал только query (GET) запрос – это самый простой вариант. Не получили новые данные – возьмём старые из кэша. А если реализовывать insert (PUT)? Нужно будет сначала внести изменения в локальную БД, выставить им (изменениям) флаг «несинхронизировано», потом при неудачной попытке GET-запроса – повторять эту попытку, например с экспоненциально возрастающей паузой (как предлагает автор паттерна) … Всё это время пользователь будет видеть добавленные данные, которых нет на сервере. Более того, что их нет на сервере, он тоже узнать не сможет (см. пункт 3); - И неприятный побочный эффект, связанный с ограниченностью взаимодействия Activity с REST (только через механизмы Content Provider) – в GUI мы не можем получить ничего, кроме данных.
К примеру, мы никогда не узнаем о причинах отсутствия данных. Ошибка в парсинге? Сервер ничего не вернул? Вообще нет сети? Результат один – нет данных. В реализации Pattern A для этой цели мы могли передать из Activity в ServiceHelper RequestListener. C Content Provider этот номер не пройдёт.
Конечно, мы можем получить данные, например через Broadcast Receiver, и в обход Content Provider, но к Pattern B это уже не будет иметь отношения.
Таким образом, при использовании Pattern B необходимо учитывать вышеуказанные моменты.
Может быть, кто-нибудь использовал этот паттерн в рабочих проектах или знает более удачные примеры реализации? Есть ли вообще смысл реализовать его более качественно (была такая идея), если за 4 года этим никто не озаботился? Буду рад видеть ответы в комментариях.
Источник