сервер с базой данных для мобильного приложения

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

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

Введение

Не открою секрета, что разработка мобильных приложений в тренде – этому способствует стремительное техническое развитие: мобильные устройства с каждым годом улучшаются по всем характеристикам и становятся доступнее для широкого круга людей. Почти каждый, кто имеет на руках мобильный гаджет (будь то смартфон, коммуникатор или планшет) пользуется приложениями: браузером, клиентом электронной почты и мгновенных сообщений, играми, бизнес или финансовыми программами. И зачастую от пользователей скрыто то, что многие из приложений взаимодействуют с удаленным сервером: обмениваются с ним данными через Интернет.
По роду деятельности (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-приложения

Собираюсь писать android-приложение. В котором буду использовать сервер. Почитал в интернете про различные сервера, ну так и не пришел к выводу что лучше и на чем писать (смотрел в сторону JSON-сервера ) Посоветуйте сервер, логика приложения в том что у каждого пользователя есть свой id. По отобранным критериям он будет получать данные с сервера, и может ставить рейтинг полученным данным(статье), и оценка идет на сервер. Какой вы могли бы порекомендовать для данного функционала?

сервер с базой данных для мобильного приложения. tBkrE. сервер с базой данных для мобильного приложения фото. сервер с базой данных для мобильного приложения-tBkrE. картинка сервер с базой данных для мобильного приложения. картинка tBkrE.

2 ответа 2

Обычно «сервер» пишут самостоятельно на удобном для разработчика языке. Так как ваше android-приложение с высокой степенью вероятности написано на Java, то и серверный функционал можно написать на Java. Пишите логику на Servlet API или Spring MVC и разворачиваете в каком-нибудь web-контейнере, типа Tomcat или Jetty. Но если вам нужен способ получать из БД данные в формате JSON с минимальными телодвижениями, то посмотрите на PostgREST.

Если писать свой сервер нет желания/времени/знаний то можно использовать какой нибудь SaaS сервис. Например, Google предлагает Firebase, который достаточно просто интегрируется в Android приложение (также есть поддержка iOS). Он предоставляет много фишек сразу из коробки, например, реалтайм синхронизацию данных на сервере и устройстве.

Конечно, функционал его ограничен и его не расширить по своему желанию, как это можно сделать с самописным сервером, но под описанную в вопросе задачу он вполне подойдёт.

сервер с базой данных для мобильного приложения. PRE3Z. сервер с базой данных для мобильного приложения фото. сервер с базой данных для мобильного приложения-PRE3Z. картинка сервер с базой данных для мобильного приложения. картинка PRE3Z.

Похожие

Подписаться на ленту

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

дизайн сайта / логотип © 2021 Stack Exchange Inc; материалы пользователей предоставляются на условиях лицензии cc by-sa. rev 2021.11.5.40661

Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

Источник

База данных для Android. Интегрируем SQLite быстро, без регистрации и СМС

сервер с базой данных для мобильного приложения. sqlite and Android h. сервер с базой данных для мобильного приложения фото. сервер с базой данных для мобильного приложения-sqlite and Android h. картинка сервер с базой данных для мобильного приложения. картинка sqlite and Android h.

Содержание статьи

Приложение или браузер

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

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

Кешируем всё

В Android из коробки база данных присутствует в виде библиотеки SQLite, которую даже не нужно как-то подключать или запрашивать на нее разрешение у пользователя. Чтобы понять, насколько она полезна, напишем полноценное приложение, которое будет загружать данные из интернета и кешировать их, а затем выдавать их в любых условиях: в дождь, мороз и дисконнект.

SQLite — легковесный фреймворк, который, с одной стороны, дает по максимуму использовать возможности SQL, с другой — бережно относится к ресурсам устройства. Его недостатки малокритичны для мобильной разработки: к примеру, нет индексов для LIKE-запросов и есть лимиты на размер базы данных.

Сериализация и JSON

Самое время поговорить о контенте: в принципе, нам абсолютно неважно, что кешировать. Тем не менее хранить в БД все подряд не стоит: если это будут какие-то разовые записи или отметки о состоянии Activity, лучше использовать SharedPreferences. Как и во «взрослых» системах, база данных предназначена для сохранения большого объема структурированной информации: каталога товаров, списка задач, новостных блоков и так далее.

Грамотные люди передаваемые по сети данные сначала сериализуют — то есть конвертируют в некую последовательность байтов. Существует несколько способов сериализации, каждый из которых хорош по-своему. Несколько лет назад был популярен формат XML, но в условиях больших объемов конвертеры XML довольно сильно грузят процессор, что критично для мобильных устройств.

На смену XML пришел формат JSON, который, пожалуй, уже стал стандартом. Он не только прост в парсинге, но и удобен для веб-разработчиков: например, он легко разбирается с помощью JavaScript. Формат JSON довольно прост и легко читается как приложениями, так и просто глазами. Для примера я взял список пользователей с несколькими параметрами — имя, описание, собственный идентификатор и картинка-аватар.

сервер с базой данных для мобильного приложения. json. сервер с базой данных для мобильного приложения фото. сервер с базой данных для мобильного приложения-json. картинка сервер с базой данных для мобильного приложения. картинка json. Рис. 1. Как парсить JSON

Xakep #217. Сценарий для взлома

Такой массив данных довольно легко раскладывается в Java-объект. Создать класс с нужным содержанием можно руками или воспользоваться конвертерами, которые ищутся по запросу json to java. Такой конвертер самостоятельно разберет поля и добавит аннотации с указанием полей.

Загрузив JSON в приложение, его нужно будет разложить по полям в подготовленный Java-объект. Для этого тоже есть готовые решения. Мне нравятся библиотека Retrofit и конвертер Gson Converter, о которых мы не раз писали. Если нет каких-то экзотических требований к сетевым запросам — Retrofit тебе однозначно подойдет.

CRUD и DAO

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

сервер с базой данных для мобильного приложения. dbScheme. сервер с базой данных для мобильного приложения фото. сервер с базой данных для мобильного приложения-dbScheme. картинка сервер с базой данных для мобильного приложения. картинка dbScheme. Рис. 2. Схема базы данных

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

SQLiteOpenHelper

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

И хотя принципы работы с БД максимально приближены к логике ООП-разработки, от синтаксиса SQL никуда не денешься. Если у тебя есть пробелы в знаниях — почитай какой-нибудь мануал для начинающих. В большинстве случаев базовых знаний будет достаточно.

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

Поскольку структура базы может меняться, нужно реализовать метод onUpgrade, который будет стирать созданное ранее.

Построение запросов

Как ты уже обратил внимание, все запросы строились через явный SQL-синтаксис, обрабатываемый методом execSQL. Он позволяет выполнить любую SQL-команду, кроме тех, что возвращают какие-либо значения. Но на практике этот метод используется только для базовой инициализации БД, для остальных случаев есть вызовы удобнее. Самый популярный способ получить данные — воспользоваться методом rawQuery. Он позволяет напрямую обратиться к базе данных, забив в аргумент классический SQL-запрос.

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

Официальная документация рекомендует не забывать освобождать ресурсы после прочтения всех необходимых данных, иначе будет утекать память. С другой стороны, если данные могут потребоваться еще раз, есть смысл Cursor не трогать — легче прочитать данные из памяти, чем сделать запрос в базу данных.

Тебе не нужно указывать значения полей при вызове метода, что, несомненно, упрощает построение запроса.

Вставка изображений

В Android есть встроенные методы для загрузки данных из сети, Retrofit можно и не привлекать.

Безопасный Select

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

Билдер принимает данные порционно, что позволяет системе проверять их на корректность. Метод setTables задает набор таблиц, из которых будет построена выборка, — это может быть как одна таблица, так и объединение нескольких.

Robolectric

В мире Android очень много инструментов для тестирования Java-кода. Сейчас мы воспользуемся фреймворком Robolectric — он позволяет прогонять код прямо на рабочей станции без использования эмуляторов и реальных устройств. Эта библиотека подключается, как и любая другая, через Gradle.

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

Типов сравнений более чем достаточно. К примеру, мы знаем, что изображение должно быть, но размер в точности до байта нам неизвестен. Тогда будет достаточно проверить, что выгружаемое изображение больше эталонного значения.

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

сервер с базой данных для мобильного приложения. robolectric. сервер с базой данных для мобильного приложения фото. сервер с базой данных для мобильного приложения-robolectric. картинка сервер с базой данных для мобильного приложения. картинка robolectric. Рис. 3. Результаты тестов

Покрывать созданные методы тестами полезно для выявления косяков, которые могут выскочить уже на стадии релиза. Некоторые разработчики даже сначала пишут тесты, а только потом исходный код проверяемых методов — этот модный прием называется TDD, Test-driven development. А при работе с базами данных они вообще незаменимы: все тесты логически изолированы, можно вносить данные без каких-либо опасений, они никогда не попадут в «настоящие» таблицы.

Outro

Источник

Архитектура мобильного клиент-серверного приложения

сервер с базой данных для мобильного приложения. image loader. сервер с базой данных для мобильного приложения фото. сервер с базой данных для мобильного приложения-image loader. картинка сервер с базой данных для мобильного приложения. картинка image loader.
К добавлению внешнего сервера рано или поздно приходит любой сложный проект. Причины, при этом, бывают совершенно различные. Одни, загружают дополнительные сведения из сети, другие, синхронизируют данные между клиентскими устройствами, третьи- переносят логику выполнения приложения на сторону сервера. Как правило, к последним относятся большинство «деловых» приложений. По мере отхода от парадигмы «песочницы», в которой все действия выполняются только в рамках исходной системы, логика выполнения процессов переплетается, сплетается, завязывается узлами настолько, что становится трудно понять, что является исходной точкой входа в процесс приложения. В этом момент, на первое место выходит уже не функциональные свойства самого приложения, а его архитектура, и, как следствие, возможности к масштабированию.
Заложенный фундамент позволяет либо создать величественный архитектурный ансамбль, либо «накурнож» — избушку на куриных ножках, которая рассыпается от одного толчка «доброго молодца» коих, за время своего существования повидала видимо — невидимо, потому что, глядя на множественные строительные дефекты заказчик склонен менять не исходный проект, а команду строителей.
Планирование — ключ к успеху проекта, но, именно на него выделяется заказчиком минимальный объем времени. Строительные паттерны — туз в рукаве разработчика, который покрывает неблагоприятные комбинации где время — оказывается решающим фактором. Взятые за основу работающие решения позволяют сделать быстрый старт, чтоб перейти к задачам, кажущиеся заказчику наиболее актуальными (как-то покраска дымоходной трубы, на еще не возведенной крыше).
В этой статье я постараюсь изложить принцип построение масштабируемой системы для мобильных устройств, покрывающей 90-95% клиент-серверных приложений, и обеспечивающей максимальное отдаление от сакраментального «накурножа».

Пока занимался доработкой данной статьи, на хабре вышла аналогичная статья (http://habrahabr.ru/company/redmadrobot/blog/246551/). Не со всеми акцентами автора я согласен, но в целом, мое видение не противоречит и не пересекается с материалом изложенным там. Читатель же, сможет определить, какой из подходов более гибкий, и более актуальный.

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

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

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

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

Общая структура приложения

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

Насколько работоспособное данное приложение? Думаю, что ни у кого нет сомнения, что используя Delphi или Visual Studio можно в момент решить эту задачу. Используя Xcode сделать это несколько сложнее, но тоже можно не сильно напрягаясь. Однако, вслед за появлением прототипа, начинают появляться вопросы масштабируемости. Становится очевидным, что для отображения графика необходимо хранить данные за предыдущий период. Не проблема, можно добавить хранилище данных внутрь формы графиков. Однако, данные могут приходить от разных провайдеров и в разных форматах. Кроме того, арифметические операции могут осуществляться с разными валютам, а значит, необходимо обеспечить их выбор. Делать такой выбор на форме графиков — несколько нелогично, хотя и возможно, однако, от таких настроек зависит что именно мы будем отображать на графике. Это означает, что если мы выносим дополнительные параметры в окно настроек, то нам придется как-то их передавать через главную форму в окно графиков. В этом случае логично будет сделать локальную переменную, в которой и хранить передаваемые параметры, и обеспечить доступ из одной форме к другой форме через главную форму. Ну и так далее. Цепочку рассуждений можно строить весьма долго, и сложность взаимодействий будет возрастать.

Конечно, данный подход требует больше усилий по программированию, и соотвественно, изначально предполагает больше времени. Однако, исходя из подзадач ясно, что во-первых, работу над ним легко распараллелить — в то время как один разработчик занят формированием ядра — другой, создает и отлаживает UI. Ядро может благополучно работать в рамках консоли, UI прощелкиваться в девайсе и, ко всему прочему, к обеим частям можно прикрутить независимые юнит-тесты. Другим несомненным достоинством является то, что второй подход значительно более масштабируем. В случае пересмотра функциональности проекта, любые изменения будут вносится многократно быстрее, потому что попросту не существует ограничительных рамок визуальных представлений. Сами визуальные формы (GUI) отображают необходимый минимум основанный на существующих в ядре задачах.

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

GitHub содержит множество библиотек, позволяющих использовать REST соединения, для iOS, наиболее востребованной является AFNetworking.

REST опирается на использование GET, POST, PUT, HEAD, PATCH и DELETE запросов. Такой зоопарк называют RESTFul ( habrahabr.ru/post/144011 ) и, как правило, он применяется только тогда, когда пишется универсальный API для работы мобильных приложений, веб-сайтов, десктопов и космических станций в одной связке.
Подавляющее большинство приложений ограничивает систему команд двумя типами, GET и POST, хотя, достаточно только одного — POST.
GET запрос передается в виде строки, которую Вы используете в браузере, а параметры для запроса передаются разделенные знаками ‘&’. POST запрос так же использует «браузерную строку» но, параметры скрывает внутри невидимого тела сообщения. Последние два утверждения повергают в уныние тех, кто с запросами ранее не сталкивался, в действительности же, технология отработана настолько, что она совершенно прозрачна для разработчика, и не приходится вникать в такие нюансы.
Выше, было описано что отправляется серверу. А вот то, что приходит от сервера — куда интересней. Если Вы используете AFNetworking, то со стороны сервера Вы получите Как правило, iOS разработчики называют JSON- оном сериализированный словарь, но это не совсем так. Истинный JSON имеет чуть более сложный формат, но в чистом виде им практически никогда пользоваться не приходится. Однако, о том, что имеется отличие знать нужно — бывают нюансы.
Если Вы работаете с сервисом, установленным на Microsoft Windows Server, то вероятнее всего, там будет использован WCF. Однако, начиная с Windows Framework 4, имеется возможность для клиентов поддерживающих только REST протокол, сделать доступ совершенно прозрачно, декларативным образом. Вы даже сможете не тратить время на получении пояснений об API — документация о системе команд генерируется автоматически IIS (майкрософтовским веб-сервером).

Ниже приводится минимальный код, для реализации Network Layer при помощи AFNetworking 2 на Objective-C.

Этого вполне достаточно чтоб передавать сетевые GET и POST сообщения. В большинстве своем, Вам не потребуется больше корректировать эти файлы.

API Layer:
Описывает команды REST и осуществляет выбор хоста. API Layer полностью отделен от знания реализации сетевых протоколов и любых других особенностей функционирования приложения. Технически, он может быть полностью заменен, без каких-либо изменений в остальных частях приложения.

Класс унаследован от ClientBase. Код класса настолько просто, что нет необходимость даже приводить его целиком — он состоит их единообразного описания API:

Как говорится: «Ничего лишнего».

Network Cache Layer:
Данный слой кеширования задействуется для ускорения сетевого обмена между клиентом и сервером на уровне iOS SDK. Выбор ответов осуществляется стороной лежащей за пределами контроля системы, и не гарантирует снижение сетевого трафика, но ускоряет его. Доступа к данным или механизмам реализации нет ни со стороны приложения, ни со стороны системы. При этом используется SQLite хранилище.

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

Вызвать нужно из любого места приложения однократно. Например из стартового слоя.

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

Каждая схема, как и каждая команда, обязана удовлетворять определенным оговоренным ранее критериям. В приведенном примере ответ сервера должен содержать два основных и одно опциональное поле.
«status» обязательное. Содержит идентификатор OK или ERROR (или код HTTP типа «200»).
«reason» обязательное Содержит текстовое описание причины ошибки, если она возникла. В противном случае — это поле пустое.
«data» опциональное. Содержит результат выполнения команды. В случае ошибки отсутствует.
Пример схемы:

Благодаря библиотеке разработанной Максимом Луниным сделать это стало очень просто. ( habrahabr.ru/post/180923 )

Код класса валидации приводится ниже

Network Items layer:
Именно на этот слое лежит ответственность за маппинг данных из JSON в десериализированное представление. Данный слой используется для описания классов, осуществляющих объектное или объектно-реляционное преобразование. В сети существует большое количество библиотек, осуществляющих объектно-релационные преобразования. Например JSON Model ( github.com/icanzilb/JSONModel ) или все та же библиотека Максима Лунина. Однако, не все так радужно. От проблем маппинга они не избавляют.

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

В классе HttpCache по-мимо методов сохранения результатов запроса имеется еще один, интересный метод:

Он позволяет извлечь из заголовка ответа сервера ключевую информацию о том через сколько секунд истечет время жизни полученного пакета (дата проэкспарится). Используя эту информацию можно записать данные в локальное хранилище, и при повторном аналогичном запросе просто прочесть ранее полученные данные. Если же метод возвращает 0, то такие данные можно не записывать.
Таким образом, на сервере можно регулировать что именно должно быть кешировано на клиенте. Стоит отметить, что используются стандартные поля заголовка. Так что, в плане стандарта велосипед не изобретается.

Путем еще одной небольшой модификации листинга 1 легко решается вопрос с очередями:

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

Проверка подключения к сети осуществляется с помощью классов AFNetworkReachabilityManager или Reachability от Apple ( developer.apple.com/library/ios/samplecode/Reachability/Introduction/Intro.html ) совместно с паттерном наблюдатель. Его устройство слишком примитивно, чтоб описывать в рамках статьи.
Однако, не все запросы должны быть отправлены в очередь. Некоторые из них могут не быть актуальными к моменту появления сети. Решить какие из команд дожны быть записаны в кеш очереди, а каки быть актуальны толко в момент вызова можно как на уровне слоя кеширования, так и на уровне слоя API.

В первом случае, в листинг 9, вместо вызова метода сохранения в очередь, необходимо вставить виртуальный метод, и унаследовать от класса ApiLayer унаследовать классы LocalCacheLayerWithQueue и LocalCacheLayerWithoutQueue. После чего в заданном виртуальном методе класса LocalCacheLayerWithQueue сделать вызов [HttpQueue request: endpoint: method:]

Во втором случае немного изменится вызов запроса из класса ApiLayer

В листинге 9 именно для такого случая предусмотрено условие if(queueAvailable).

Так же, отдельным вопросом является вопрос кеширования изображений. В общем-то, вопрос не сложный, и оттого, имеющий бесконечное количество реализаций. К примеру, библиотека SDWebImage делает это весьма успешно: ( github.com/rs/SDWebImage ).

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

Приведу пример асинхронной загрузки изображения из сети, с коррекцией ошибки MIME (к примеру, Amazon часто отдает неправильный MIME type, в результате чего, их же веб-сервер отправляет изображение, не как двоичный файл с картинкой, а как поток данных).

Метод может казаться весьма избыточным, но легко модифицируемым к конкретным нуждам разработчика. Из важных моментов следует отметить то, что в качестве ключа для кеширования используется хеш URL изображения. Практически невозможно чтоб при таком подходе случилась коллизия в рамках файловой системы устройства.
При каждом чтении файла из кеша, у него модифицируется дата доступа. Файлы которые не перечитываются долгое время можно спокойно удалить еще на старте приложения.

Когда речи идет о чтении файла из бандла приложения, имеется нюанс, который забывают разработчики: iOS SDK предоставляет нам такие методы как [UIImage imageNamed:] и [UIImage imageWithContentsOfFile:]. Использовать первый проще, но он существенно влияет на загруженность памяти — дело в том, что файл загруженный при помощи него, остается в памяти устройства, до тех пор, пока приложение не будет завершено. Если это файл, который имеет большой объем, то это может стать проблемой. Рекомендуется использовать второй метод, как можно чаще. Кроме того, полезно сделать небольшое усовершенствование в метод загрузки:

Теперь Вам не придется задаваться вопросом, в какой резолюции присутствует файл.

Workflows layer:
Все реализованные алгоритмы, которые не относятся к слоям ядра, и не представляют собой GUI должны быть вынесены в классы специфических последовательностей рабочих процессов. Каждый из этих процессов оформляется в своем стиле, и подключается к основной части приложения путем добавления ссылок на экземпляр соответствующего класса в GUI. В подавляющем большинстве случаев, все эти процессы являются не визуальными. Однако имеются некоторые исключения, например, когда необходимо осуществить длинную последовательность предопределенных кадров анимации, с заданными алгоритмами отображения
Вызывающий код должен иметь минимальные знания об этой функциональности. Все настройки flow должны быть инакапсулированы. Google в качестве примера приводит код для уведомления из сервера аналитики, и предлагает включить его в место, где событие возникает.

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

Существуют довольно развитые рабочие процессы, логика функционирования которых зависит от внутренного состояния. Такие процессы должны быть реализованы при помощи паттернов «Стратегия» или «Машина состояний». Как правило, совместно с паттерном «стратегия» используется паттерн «медиатор» который опосредует обращение к тому или иному алгоритму.
Один из часто используемых процессов — процесс авторизации пользователя — очевидный претендент на рефаторинг с использованием паттерна «машины состояний». При этом, именно на этом flow должна лежать ответственность за «автоматическую» авторизацию пользователя, а не рекурсивным образом вызываться из абстрактных слоев (Network Layer, или Validation Items).

Каждый вызов слоев ядра сопровождается передачей объекта обратного вызова (callback), и именно через него должно быть возвращено управление в приложение при успешном выполнении команды или возникновения ошибок. Ни в коем случае не должен допускаться неявный вызов слоев ядра, объектами рабочей последовательности.
Так же, ни в коем случае нельзя допускать, чтоб какие-либо универсальные визуальные контролы зависели бы от состояния рабочих последовательностей. Если это критически необходимо, такие контролы должны быть приватизированы последовательностью. Доступ к состоянию контролов может осуществляться через свойства самих контролов, наследование и переопределение методов, и, в крайнем случае, через реализацию делегатных методов и путем создания категорий. Ключевым в этом витиеватом посыле есть то, что категории — это зло, которого следует избегать. Т. е. я не предлагаю отказываться от категорий, но при прочих равных условиях, код без них легче читается и несомненно более предсказуемый.

Local storage:
Желание разработчиков находится в тренде новых технологий, порой, сталкивается со здравым смыслом, и, последний часто проигрывает. Одно из веяний моды было использование локального хранилища на основе CoreData. Некоторые разработчики настаивали, что его нужно использовать в как можно большем количестве проектов, не смотря на то, что даже сама Apple признавала, что есть определенные трудности.
Существует большое количество способов сохранение временных данных в постоянном хранилище устройства. Использование CoreData оправдано в том случае, когда нам необходимо хранить большое количество редко обновляемых данных. Однако, если в приложении имеется несколько сот записей, и ни постоянно обновляются скопом использование CoreData в этих целях неоправданно дорого. Таким образом, получается, что большую часть времени ресурсов устройство тратит на синхронизацию данных полученных из сети, с теми данными которые уже есть на устройстве, несмотря на то, что весь массив данных, будет обновлён во время следущей сессии.

Использование CoreData ( habrahabr.ru/post/191334 ), кроме того, требует также соблюдение определённых процедур, алгоритмов и архитектурных решений, что ограничивает нас в выборе стратегии разработки, а так же существенно осложняет механизмы отладки нашего приложения.

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

Локальное хранилище на основе файловой системы

Средства чтения / записи iOS SDK делает NSDictionary идеальным форматом сохранения относительно небольших короткоживущих данных, поскольку для этого применяются однопроходные алгоритмы.

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

Отрицательной стороной такого подхода считается, что это плохо влияет на производительность устройства, однако, изучение вопроса показывает, что объем таких данных не превышает 5Кбайт, данные загружаются в память мгновенно, единым блоком, и таким же образом освобождаются из памяти, сразу же после того, как в них отпадает необходимость, например, когда ViewController перестает существовать. В то же время чтение данных блоками (построчно) из базы данных SQL порождает большое количество объектов (на уровне выходящем за рамки контроля приложения), которые суммарно превышают указанный объем, к тому же, создают дополнительную нагрузку на процессор. Использование центрального хранилище оправдано тогда, когда данные должны сохраняться долгое время, на протяжении многих сессий работы приложения. При этом, данные из сети загружаются частично.

Локальное хранилище на основе CoreData.

CoreData не предоставляет возможности для использование сериализированных данных. Все данные должны быть подвергнуты объектно-реляционным преобразованиям, до их использования слоем локального хранилища. После получения данных от команды API profile, происходит передача данных в метод категории copyDataFromRemoteJSON, где из словаря извлекаются данные, а затем уже сохраняются в соответствующем управляемом объекте (потомокк класса NSManagedObject).
Вот пример того, как это происходит:

Еще лучшим подходом было бы, если бы callback из API мог бы возвращать валидизированные сериализированные данные, упакованные, к тому же, в управляемый объект.

Преимущества данного подхода:
Гипотетически считается, что ленивая загрузка при помощи NSFetchController позволяет существенно ускорить отображение данных из базы данных, когда их количество составляет несколько тысяч записей. Так же, добавление данных в базу уменьшает количество передаваемой информации по сети. Данные добавляются. Те что есть- показываются пользователю. Пользователь может удалить данные которые ему не нужны. Данные добавляются в те, объекты, которые уже существуют, как элементы их массива.

При использовании библиотеки MagicalRecords возникает ситуация, когда для правильного функционирования приложения табличное представление должно быть частью UITableViewController, иначе становится затруднительным использование NSFetchController лежащий в основе загрузки данных CoreData. Таким образом, существует зависимость в использовании пользовательского интерфейса, от локального хранилища. Т. е. имплементация CoreData ограничивает в разработке UI.

Не смотря на высказанные возражения, использование CoreData может, действительно, потенциально увеличить производительность при возрастании объема данных, в том случае, если воспользоваться следующими альтернативами:

Альтернатива 1
Произвести нормализацию данных API сервера. Сервер должен возвращать не полный иерархический объект, с множеством вложенных сущностей, а множество мелких объектов, которые легко добавляются в базу данных.
В этом случае:
Загружаться будут небольшие порции свежих данных, что уменьши сетевой трафик.
Приложение сможет сделать запрос к серверу с идентификаторами объектов, чтоб сервер вернул список того, что необходимо удалить.
Отпадает необходимость в синхронизации получаемых данных для каждой загружаемой записи.

Заключение:
Статья получилась довольно длинной, и, сомневаюсь, что большинство читателей осилят ее до конца. По этой причине, часть, связанную с GUI я решил отсюда выкинуть. Во-первых, она относилась к построению пользовательского интерфейса через UITabbar, а во-вторых, в одной из скайп групп, состоялась весьма интересная дискуссия относительно использования широко известных паттернов MVC и MVVM. Излагать принципы построения интерфейса не имеет смысл без скурпулезного изложения существущих практик и подходов, которые заводят разработчиков в тупик. Но это тема большой еще одной многостраничной статьи. Здесь же, я постарался рассмотреть лишь вопросы, связанные с функционированием ядра приложения.
Если читатели проявят достаточный интерес к этой тематике, то в ближайшее время постараюсь выложить исходные классы, для использование в качестве шаблона приложения.

Источник

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

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