серверная часть для мобильного приложения

Простой клиент-сервер на Android (интернет-мессенджер)

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

Поехали. Многие мобильные приложения (и не только) используют архитектуру клиент-сервер. Общая схема, думаю, понятна.

серверная часть для мобильного приложения. 72ff3cc1380e4a05a3a22a614b2d0bfd. серверная часть для мобильного приложения фото. серверная часть для мобильного приложения-72ff3cc1380e4a05a3a22a614b2d0bfd. картинка серверная часть для мобильного приложения. картинка 72ff3cc1380e4a05a3a22a614b2d0bfd.

Уделим внимание каждому элементу и отметим:

серверная часть для мобильного приложения. b0aeddc9d49e4525966d138e485db8f0. серверная часть для мобильного приложения фото. серверная часть для мобильного приложения-b0aeddc9d49e4525966d138e485db8f0. картинка серверная часть для мобильного приложения. картинка b0aeddc9d49e4525966d138e485db8f0.

Клиент, установленный на устройстве А, посылает сообщение для клиента, установленного на устройстве Б. И наоборот. Сервер играет роль связующего звена между устройством А и Б… С, Д… и т.д. Также он играет роль «накопителя» сообщений, для их восстановления, на случай удаления на одном из клиентских устройств.

Для хранения сообщений используем SQL БД как на сервере, так и на устройствах-клиентах (в принципе, вся работа клиентов интернет-мессенджеров и сводится к постоянной синхронизации локальной и удаленной БД с сообщениями). Дополнительно, наш интернет-чат будет уметь стартовать вместе с запуском устройства и работать в фоне. Взаимодействие будет происходить путем HTTP запросов и JSON ответов.

Более логично, если синхронизация происходит через порт/сокет, это с одной стороны упрощает задачу (не нужно циклично слать HTTP запросы на проверку новых сообщений, достаточно проверять состояние прослушиваемого сокета), но с другой стороны, это усложняет создание серверной части приложения.

Делаем сервер

Для реализации «сервера», нам нужно зарегистрироваться на любом хостинге, который дает возможность работы с SQL и PHP.

Создаем пустую SQL БД, в ней создаем таблицу.

Структура запросов к api:

Клиентская часть

Теперь структура Android приложения:

серверная часть для мобильного приложения. 6898c53f8075409ba4d2137fd223d685. серверная часть для мобильного приложения фото. серверная часть для мобильного приложения-6898c53f8075409ba4d2137fd223d685. картинка серверная часть для мобильного приложения. картинка 6898c53f8075409ba4d2137fd223d685.

В фоне работает FoneService.java, который, в отдельном потоке, каждые 15 секунд делает запрос на сервер. Если ответ сервера содержит новые сообщения, FoneService.java записывает их в локальную БД и отправляет сообщение ChatActivity.java о необходимости обновить ListView, с сообщениями. ChatActivity.java (если она в этот момент открыта) получает сообщение и обновляет содержимое ListView из локальной БД.

Отправка нового сообщения из ChatActivity.java происходит сразу на сервер, минуя FoneService.java. При этом наше сообщение НЕ записывается в локальную БД! Там оно появится только после получения его назад в виде ответа сервера. Такую реализацию я использовал в связи с важным нюансом работы любого интернет-чата — обязательной группировкой сообщений по времени. Если не использовать группировку по времени, будет нарушена последовательность сообщений. Учитывая, что клиентские приложения просто физически не могут быть синхронизированы с точностью до миллисекунд, а возможно будут работать даже в разных часовых поясах, логичнее всего будет использовать время сервера. Так мы и делаем.

Создавая новое сообщение, мы передаем запросом на сервер: имя автора сообщения, имя получателя сообщения, текст сообщения. Получая эту запись назад, в виде ответа сервера, мы получаем то, что отправляли + четвертый параметр: время получения сообщения сервером.

Источник

ASP.NET Core: Создание серверных служб для мобильных приложений

Представляем вторую часть из серии статей, посвящённых разработке на ASP.NET Core. В этом обучающем материале вы узнаете, как создавать серверные службы с помощью ASP.NET Core MVC для поддержки мобильных приложений.

серверная часть для мобильного приложения. e5d47765f45a4f3dbc9f15cb60620f69. серверная часть для мобильного приложения фото. серверная часть для мобильного приложения-e5d47765f45a4f3dbc9f15cb60620f69. картинка серверная часть для мобильного приложения. картинка e5d47765f45a4f3dbc9f15cb60620f69.

Второй цикл статей по ASP.NET Core

Первый цикл статей можно найти здесь.

Образец мобильного приложения

Мобильные приложения могут без труда обмениваться данными с серверными службами ASP.NET Core. Здесь можно скачать образец кода серверных служб.

В данном материале в качестве клиента используется приложение Xamarin Forms ToDoRest. Оно включает отдельные клиенты для устройств под Android, iOS и Windows. По ссылке выше вы найдёте руководство, которое поможет создать приложение (и установить необходимые бесплатные инструменты Xamarin), а также сможете скачать образец решения Xamarin. В него входит проект двух служб ASP.NET веб-API, на замену которым приходит приложение ASP.NET Core из этой статьи (со стороны клиента изменения не понадобятся).

серверная часть для мобильного приложения. image loader. серверная часть для мобильного приложения фото. серверная часть для мобильного приложения-image loader. картинка серверная часть для мобильного приложения. картинка image loader.

Функции

Приложение ToDoRest поддерживает составление списков, добавление, удаление и обновление элементов To-Do. Каждый элемент наделён своим идентификатором, названием, примечаниями и свойством, которое указывает, выполнен ли элемент.

В основном представлении элементов, как показано выше, имеется название каждого элемента, а наличие флажка указывает, был ли он выполнен.

Коснитесь значка +, чтобы открыть диалоговое окно для добавления элементов:

серверная часть для мобильного приложения. image loader. серверная часть для мобильного приложения фото. серверная часть для мобильного приложения-image loader. картинка серверная часть для мобильного приложения. картинка image loader.

Коснитесь элемента в главном списке, чтобы открыть диалоговое окно для редактирования названия, примечания и статуса выполнения, либо чтобы удалить элемент:

серверная часть для мобильного приложения. image loader. серверная часть для мобильного приложения фото. серверная часть для мобильного приложения-image loader. картинка серверная часть для мобильного приложения. картинка image loader.

Создание проекта ASP.NET Core

Создайте новое веб-приложение ASP.NET Core в Visual Studio. Выберите шаблон веб-API и отключите аутентификацию. Присвойте проекту имя ToDoApi.

серверная часть для мобильного приложения. image loader. серверная часть для мобильного приложения фото. серверная часть для мобильного приложения-image loader. картинка серверная часть для мобильного приложения. картинка image loader.

Примечание: обязательно запустите приложение напрямую, а не через IIS Express, который по умолчанию игнорирует не локальные запросы. Выполните dotnet run из командной строки либо выберите название приложения из раскрывающегося меню Debug Target на панели инструментов Visual Studio.

Добавьте класс модели для представления элементов To-Do. Отметьте обязательные поля с помощью атрибута [Required] :

В этом примере при реализации используется частная коллекция элементов:

Настройте реализацию в Startup.cs:

Теперь можно перейти к созданию ToDoItemsController.

Создание контроллера

Для работы контроллера необходим параметр IToDoRepository; запросите экземпляр этого типа через конструктор контроллера. В среде выполнения этот экземпляр будет предоставлен благодаря поддержке платформы для внедрения зависимости.

Этот API поддерживает четыре команды HTTP для операций создания, чтения, обновления и удаления (CRUD) в источнике данных. Самая простая операция — Read (чтение), она соответствует запросу HTTP Get.

Чтение элементов

Метод List выдает код ответа 200 OK и список всех элементов ToDo, сериализованных как JSON.

Вы можете протестировать новый метод API с помощью ряда инструментов, например Postman, как показано ниже:

серверная часть для мобильного приложения. image loader. серверная часть для мобильного приложения фото. серверная часть для мобильного приложения-image loader. картинка серверная часть для мобильного приложения. картинка image loader.

Создание элементов

Внутри метода проверяется, правильно ли составлен элемент и существовал ли он ранее в хранилище данных; если ошибок нет, он добавляется с помощью репозитория. ModelState.IsValid выполняет проверку модели; это следует сделать в каждом методе API, который принимает вводимые пользователем данные.

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

серверная часть для мобильного приложения. image loader. серверная часть для мобильного приложения фото. серверная часть для мобильного приложения-image loader. картинка серверная часть для мобильного приложения. картинка image loader.

В ответе метод выдает только что созданный элемент.

Обновление элементов

Чтобы протестировать Postman, измените команду на PUT и добавьте ID обновляемой записи в URL. Укажите данные обновляемого объекта в теле запроса.

серверная часть для мобильного приложения. image loader. серверная часть для мобильного приложения фото. серверная часть для мобильного приложения-image loader. картинка серверная часть для мобильного приложения. картинка image loader.

При успешном выполнении метод выдает ответ NoContent (204), обеспечивая тем самым согласованность с существующим API.

Удаление элементов

Помните, что при тестировании функции удаления в тело запроса добавлять ничего не нужно.

Источник

Разработка сервера мобильных клиентов

Обратная сторона мобильных клиентов — сервер.

Введение

Не открою секрета, что разработка мобильных приложений в тренде – этому способствует стремительное техническое развитие: мобильные устройства с каждым годом улучшаются по всем характеристикам и становятся доступнее для широкого круга людей. Почти каждый, кто имеет на руках мобильный гаджет (будь то смартфон, коммуникатор или планшет) пользуется приложениями: браузером, клиентом электронной почты и мгновенных сообщений, играми, бизнес или финансовыми программами. И зачастую от пользователей скрыто то, что многие из приложений взаимодействуют с удаленным сервером: обмениваются с ним данными через Интернет.
По роду деятельности (Java разработчик серверных приложений) мне в команде приходится разрабатывать сервера для мобильных клиентов (за последние 2 года участвовал в реализации 3-х таких проектов для зарубежных компаний). Определился набор Java-технологий для решения задач такого рода, который варьируется в зависимости от требований и целесообразности (другими словами — желания), благо свобода при выборе технологий позволяет экспериментировать. Сформировавшейся точкой зрения и опытом хотел бы поделиться с сообществом.

Требования

Особенностью является то, что формируются требования и для серверного, и для клиентского приложения, которые в ряде случаев взаимосвязаны. Для начала опишу базовые требования в контексте механизма обмена данными:
• кроссплатформенность клиента: зачастую важно обеспечить поддержку разных платформ — Android, iOS, Windows Phone и пр. Редко заказчик довольствуется одним видом устройств.
• быстродействие: должна обеспечиваться достаточная для workflow скорость работы, комфортный отклик на графическом интерфейсе пользователя;
• простота: чем проще API протокола, тем меньше времени уходит на реализацию и поддержку кода, тем меньше может быть квалификация разработчика;
• эффективность: чем сложнее реализация протокола, тем больше потребляется ресурсов мобильного устройства, которые ограничены.

Дополнительные требования зависят от специфики приложения:
• масштабируемость сервера – для SaaS, социальных приложений, где в идеале ожидается большой поток посетителей, это условие обязательно. Для бизнес приложений, где есть ограничения по числу пользователей или численность прогнозируется, данное свойство не требуется;
• интерактивность: ряд приложений нужно обеспечить механизмом нотификаций – сообщить приложению (пользователю) о наступлении определенных событий, передать сообщение пользователю. Данным свойством должна обладать, например, биржевая система или автоматический диспетчер такси.
• открытое API: предполагается, что сторонние разработчики могут воспользоваться функционалом системы посредством документированного протокола. Ведь клиентом может быть как мобильное, так и внешнее серверное приложение.
• другие требования…

Команда

Состав проектной команды для разработки системы в идеале может быть следующим:
• менеджер проекта: управляет, контролирует проект, напрямую взаимодействует с заказчиком;
• разработчик серверного приложения: разрабатывает сервер бизнес логики, базу данных, сетевой протокол;
• разработчик приложения администратора: разрабатывает Web приложение, пользовательский интерфейс для настройки и управления серверным приложением;
• разработчик клиентского приложения для Android;
• разработчик клиентского приложения для iOS;
• разработчик клиентского приложения для …
• тестировщик: тестирует приложение администратора и клиентские приложения.

Внимательный читатель заметит, что в случае написания серверного приложения с графическим интерфейсом, например, на HTML5, можно сэкономить. В этом случае не требуется разработка клиентских приложений – интерфейс пользователя предоставляет браузер. Данная статья не рассматривает такой случай, идет речь о разработке ”родных” (native) приложений для мобильных устройств.

Мне доводилось работать в команде с полным составом, но будет реалистами – не всегда человеческие ресурсы и бюджет позволяет собрать такую команду. И иногда роли приходится совмещать: менеджер проекта + разработчик серверного приложения, разработчик клиентского приложения + тестировщик.

Технологии, инструменты, библиотеки

Для разработки сервера мобильных клиентов обычно использую следующий стек “свободных” технологий:
• Apache Tomcat – контейнер сервлетов;
• MySQL – СУБД;
• Subversion – система версионного контроля;
• Maven – фреймворк для автоматизации сборки проектов;
• JUnit – обеспечит эффективность автоматического тестирования приложений;
• Apache Log4j – библиотека логгирования;
• Jenkins – система непрерывной интеграции;
• Hibernate – ORM (настройки, конфигурация в properties, xml файлах и в аннотациях);
• hibernate-generic-dao – реализация DAO от Google, реализует основные методы для работы с данными базы данных, упрощает реализацию фильтрации и сортировки в методах;
• Spring – реализация аутентификации и авторизации (security), контейнер сервисов и бинов (конфигурация в xml файлах и в аннотациях), используем также при создании тестов.

В зависимости от специфики системы и требований к ней использую один из 2-ух вариантов реализации протокола обмена данными.
Когда требуются кроссплатформенность, быстродействие, простота, эффективность, масштабируемость, открытое API, то беру Jersey – реализацию Web-сервисов REST (RESTful Web services). Эта библиотека позволяет использовать сериализацию данных в формате JSON или(и) XML. Конфигурация REST ведется посредством аннотаций. Для обмена с мобильными устройствами взят формат JSON по причине того, что имеет более простую реализацию на стороне клиента (по этой причине не используем “классические” Web-сервисы), генерируется меньший объем трафика. Jersey позволяет настроиться на наиболее подходящий “вид” JSON.
В ином случае, если необходимы кроссплатформенность, высокое быстродействие, простота, эффективность, интерактивность, то беру
• Apache MINA – framework для создания сетевых приложений,
• Google protobuf – библиотека кодирования и декодирования структурированных данных. Структура данных определяется заголовочными файлами *.proto, компилятор генерирует из них Java классы (также есть возможность генерации для других языков программирования: C++, Objective-C и т. д., что обеспечивает свойство кроссплатформенности);
• java.util.concurrent – используем стандартный пакет.
Данный вариант может масшабироваться, но на это требуется закладываться на этапе проектирования на уровне архитектуры, учитывая бизнес логику.

Рассмотрим гипотетическую задачу на примере выбора технологий для реального SaaS сервиса – “Аукцион услуг “Аукнем”, который позволяет людям сформировать заказ на выполнение требуемых услуг или работ, а организациям в свою очередь оставить для них свои предложения. Берем все базовые требования по умолчанию. Ввиду того, что регистрация в этой системе свободная и бесплатная, то однозначно к ним требуется добавить масштабируемость. А что на счет интерактивности? Было бы здорово сообщать подрядчикам (исполнителям) о создании новых заказов, а заказчиков информировать о поступивших предложениях в тот же миг в приложении, а не только по электронной почте. На основания этого возьмем для реализации Apache MINA, Google protobuf. Смотрим следующее свойство — открытое API. Сервис общедоступный, потому предположим, что внешние разработчики могут проявить интерес к интеграции с ним. Постойте! Не все так просто. Протокол на базе Apache MINA достаточно сильно зависит от реализации и интеграция без знания нюансов отнюдь не прозрачна. В такой ситуации придется взвесить, какой фактор важнее и сделать выбор.

Источник

Android архитектура клиент-серверного приложения

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

серверная часть для мобильного приложения. image loader. серверная часть для мобильного приложения фото. серверная часть для мобильного приложения-image loader. картинка серверная часть для мобильного приложения. картинка image loader.

Конечно, сейчас уже не 2010 год, когда разработчикам приходилось использовать знаменитые паттерны A/B/C или вообще запускать AsyncTask-и и сильно бить в бубен. Появилось большое количество различных библиотек, которые позволяют вам без особых усилий выполнять запросы, в том числе и асинхронно. Эти библиотеки весьма интересны, и нам тоже стоит начать с выбора подходящей. Но для начала давайте немного вспомним, что у нас уже есть.

Раньше в Android единственным доступным средством для выполнения сетевых запросов был клиент Apache, который на самом деле далек от идеала, и не зря сейчас Google усиленно старается избавиться от него в новых приложениях. Позже плодом стараний разработчиков Google стал класс HttpUrlConnection. Он ситуацию исправил не сильно. По-прежнему не хватало возможности выполнять асинхронные запросы, хотя модель HttpUrlConnection + Loaders уже является более-менее работоспособной.

2013 год стал в этом плане весьма эффективным. Появились замечательные библиотеки Volley и Retrofit. Volley — библиотека более общего плана, предназначенная для работы с сетью, в то время как Retrofit специально создана для работы с REST Api. И именно последняя библиотека стала общепризнанным стандартом при разработке клиент-серверных приложений.

У Retrofit, по сравнению с другими средствами, можно выделить несколько основных преимуществ:
1) Крайне удобный и простой интерфейс, который предоставляет полный функционал для выполнения любых запросов;
2) Гибкая настройка — можно использовать любой клиент для выполнения запроса, любую библиотеку для разбора json и т.д.;
3) Отсутствие необходимости самостоятельно выполнять парсинг json-а — эту работу выполняет библиотека Gson (и уже не только Gson);
4) Удобная обработка результата и ошибок;
5) Поддержка Rx, что тоже является немаловажным фактором сегодня.

Если вы еще не знакомы с библиотекой Retrofit, самое время изучить ее. Но я в любом случае сделаю небольшое введение, а заодно мы немного рассмотрим новые возможности версии 2.0.0 (советую также посмотреть презентацию по Retrofit 2.0.0).

В качестве примера я выбрал API для аэропортов за его максимальную простоту. И мы решаем самую банальную задачу — получение списка ближайших аэропортов.

В первую очередь нам нужно подключить все выбранные библиотеки и требуемые зависимости для Retrofit:

Мы будем получать аэропорты в виде списка объектов определенного класса.

Создаем сервис для запросов:

Примечание про Retrofit 2.0.0
Раньше для выполнения синхронных и асинхронных запросов мы должны были писать разные методы. Теперь при попытке создать сервис, который содержит void метод, вы получите ошибку. В Retrofit 2.0.0 интерфейс Call инкапсулирует запросы и позволяет выполнять их синхронно или асинхронно.

Теперь создадим вспомогательные методы:

Отлично! Подготовка завершена, и теперь мы можем выполнить запрос:

Все кажется очень простым. Мы без особых усилий создали нужные классы, и уже можем делать запросы, получать результат и обрабатывать ошибки, и все это буквально за 10 минут. Что же еще нужно?

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

В данной ситуации у нас есть несколько вариантов. Можно воспользоваться любой библиотекой, которая обеспечивает грамотную работу с многопоточностью. Здесь идеально подходит фреймворк Rx, тем более что Retrofit его поддерживает. Однако построить архитектуру с Rx или даже просто использовать функциональное реактивное программирование — это нетривиальные задачи. Мы пойдем по более простому пути: воспользуемся средствами, которые предлагает нам Android из коробки. А именно, лоадерами.

Лоадеры появились в версии API 11 и до сих пор остаются очень мощным средством для параллельного выполнения запросов. Конечно, в лоадерах можно делать вообще что угодно, но обычно их используют либо для чтения данных с базы, либо для выполнения сетевых запросов. И самое важное преимущество лоадеров — через класс LoaderManager они связаны с жизненным циклом Activity и Fragment. Это позволяет использовать их без опасения, что данные будут утрачены при закрытии приложения или результат вернется не в тот коллбэк.

Обычно модель работы с лоадерами подразумевает следующие шаги:
1) Выполняем запрос и получаем результат;
2) Каким-то образом кэшируем результат (чаще всего в базе данных);
3) Возвращаем результат в Activity или Fragment.

Примечание
Такая модель хороша тем, что Activity или Fragment не думают, как именно получаются данные. Например, с сервера может вернуться ошибка, но при этом лоадер вернет закэшированные данные.

Давайте реализуем такую модель. Я опускаю подробности того, как реализована работа с базой данных, при необходимости вы можете посмотреть пример на Github (ссылка в конце статьи). Здесь тоже возможно множество вариаций, и я буду рассматривать их по очереди, все их преимущества и недостатки, пока, наконец, не дойду до модели, которую считаю оптимальной.

Примечание
Все лоадеры должны работать с универсальным типом данных, чтобы можно было использовать интерфейс LoaderCallbacks в одной активити или фрагменте для разных типов загружаемых данных. Первым таким типом, который приходит на ум, является Cursor.

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

Loader + ContentProvider + асинхронные запросы

Предусловия: есть классы для работы с базой данных SQLite через ContentProvider, есть возможность сохранять сущности в эту базу.

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

Тогда лоадер для загрузки аэропортов может выглядеть следующим образом:

И теперь мы наконец можем использовать его в UI классах:

Как видно, здесь нет ничего сложного. Это абсолютно стандартная работа с лоадерами. На мой взгляд, лоадеры предоставляют идеальный уровень абстракции. Мы загружаем нужные данные, но без лишних знаний о том, как именно они загружаются.

Эта модель стабильная, достаточно удобная для использования, но все же имеет недостатки:
1) Каждый новый лоадер содержит свою логику для работы с результатом. Этот недостаток можно исправить, и частично мы сделаем это в следующей модели и полностью — в последней.
2) Второй недостаток намного серьезнее: все операции с базой данных выполняются в главном потоке приложения, а это может приводить к различным негативным последствиям, даже до остановки приложения при очень большом количестве сохраняемых данных. Да и в конце концов, мы же используем лоадеры. Давайте делать все асинхронно!

Loader + ContentProvider + синхронные запросы

Спрашивается, зачем мы выполняли запрос асинхронно с помощью Retrofit-а, когда лоадеры и так позволяют нам работать в background? Исправим это.

Эта модель упрощенная, но основное отличие заключается в том, что асинхронность запроса достигается за счет лоадеров, и работа с базой уже происходит не в основном потоке. Наследники базового класса должны лишь вернуть нам объект типа Cursor. Теперь базовый класс может выглядеть следующим образом:

И тогда реализация абстрактного метода может выглядеть следующим образом:

Работа с лоадером в UI у нас никак не изменилась.

По факту, эта модель является модификацией предыдущей, она частично устраняет ее недостатки. Но на мой взгляд, этого все равно недостаточно. Тут можно снова выделить недостатки:
1) В каждом лоадере присутствует индивидуальная логика сохранения данных.
2) Возможна работа только с базой данных SQLite.

И наконец, давайте полностью устраним эти недостатки и получим универсальную и почти идеальную модель!

Loader + любое хранилище данных + синхронные запросы

Перед рассмотрением конкретных моделей я говорил о том, что для лоадеров мы должны использовать единый тип данных. Кроме Cursor ничего на ум не приходит. Так давайте создадим такой тип! Что должно в нем быть? Естественно, он не должен быть generic-типом (иначе мы не сможем использовать коллбэки лоадера для разных типов данных в одной активити / фрагменте), но в то же время он должен быть контейнером для объекта любого типа. И вот здесь я вижу единственное слабое место в этой модели — мы должны использовать тип Object и выполнять unchecked преобразования. Но все же, это не столь существенный минус. Итоговая версия данного типа выглядит следующим образом:

Данный тип может хранить результат выполнения запроса. Если мы хотим что-то делать для конкретного запроса, нужно унаследоваться от этого класса и переопределить / добавить нужные методы. Например, так:

Отлично! Теперь напишем базовый класс для лоадеров:

Этот класс лоадера является конечной целью данной статьи и, на мой взгляд, отличной, работоспособной и расширяемой моделью. Хотите перейти с SQLite, например, на Realm? Не проблема. Рассмотрим это в качестве следующего примера. Классы лоадеров не изменятся, изменится только модель, которую вы бы в любом случае редактировали. Не удалось выполнить запрос? Не проблема, доработайте в наследнике метод apiCall. Хотите очистить базу данных при ошибке? Переопределите onError и работайте — этот метод выполняется в фоновом потоке.

А любой конкретный лоадер можно представить следующим образом (опять-таки, покажу только реализацию абстрактного метода):

Примечание
При неудачно выполненном запросе будет выброшен Exception, и мы попадем в catch-ветку базового лоадера.

В итоге мы получили следующие результаты:
1) Каждый лоадер зависит исключительно от своего запроса (от параметров и результата), но при этом он не знает, что он делает с полученными данными. То есть он будет меняться только при изменении параметров конкретного запроса.
2) Базовый лоадер управляет всей логикой выполнения запросов и работы с результатами.
3) Более того, сами классы модели тоже не имеют понятия о том, как устроена работа с базой данных и прочее. Все это вынесено в отдельные классы / методы. Я этого нигде не указывал явно, но это можно посмотреть в примере на Github — ссылка в конце статьи.

Вместо заключения

Чуть выше я обещал показать еще один пример — переход с SQLite на Realm — и убедиться, что мы действительно не затронем лоадеры. Давайте сделаем это. На самом деле, кода здесь совсем чуть-чуть, ведь работа с базой у нас сейчас выполняется лишь в одном методе (я не учитываю изменения, связанные со спецификой Realm, а они есть, в частности, правила именования полей и работа с Gson; их можно посмотреть на Github).

И изменим метод save в AirportsResponse:

Вот и все! Мы элементарным образом, не затрагивая классы, которые содержат другую логику, изменили способ хранения данных.

Все-таки заключение

Хочу выделить один достаточно важный момент: мы не рассмотрели вопросы, связанные с использованием закэшированных данных, то есть при отстуствии интернета. Однако стратегия использования закэшированных данных в каждом приложении индивидуальна, и навязывать какой-то определенный подход я не считаю правильным. Да и так статья растянулась.

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

Спасибо, что дочитали до конца. Удачной разработки!

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *