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

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

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

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

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

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

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

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

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

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

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

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

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

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

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

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

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

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

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

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

Источник

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

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

Введение

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

Источник

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

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

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

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

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

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

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

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

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Функции

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

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

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

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

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

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

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

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

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Примечание: обязательно запустите приложение напрямую, а не через 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, как показано ниже:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

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

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

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

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

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

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

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

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

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

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

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

Источник

Простое клиент-серверное приложение для Android с нуля

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

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Урок состоит из трёх частей:

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

Цель урока — объяснить в общих чертах принципы работы клиент-серверных приложений. Если вы можете установить и настроить IDE, немного знаете Java и\или Kotlin и можете самостоятельно написать простое приложение, этот урок для вас. Если же нет, боюсь, будет сложно. Объяснять постараюсь максимально подробно и понятно, но без фанатизма. Все исходники доступны на github.

Ретроспектива

Я перечитал данную статью через 10 месяцев после её публикации. За это время я многому научился и сейчас сделал бы всё по-другому. Но, пусть всё остаётся так, как написано изначально.

Данные

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

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

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

Напишем небольшую программу для уменьшения изображений. Будем использовать IntelliJ IDEA Community Edition. Если не установлен JDK, устанавливаем. Создадим общую папку для проекта и назовём её Wallpapers, создадим в ней ещё три папки: Client, Server и Resizer. Запускаем IDEA и создаём Gradle Java проект:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Нажимаем Next и заполняем оставшиеся данные, примерно, как на следующих скриншотах:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

В качестве Project location указываем ранее созданную папку Wallpapers/Resizer:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Открываем файл build.gradle и приводим его к следующему виду:

В dependencies подключаются три библиотеки: junit jupiter api для тестирования, junit jupiter engine для запуска тестов и imgscalr для ресайза изображений.

Создаём в main/java/com.illuzor.lesson.resizer класс Paths в котором инициализируем статические константы для путей к папкам:

Создаём класс Resizer с одним методом resize():

Выглядит громоздко, но всё довольно просто. Первый цикл проходит по папкам в images и создаёт папки с такими же именами в images_previes, второй аналогично проходит по файлам категории и создаёт соответствующие уменьшенные файлы изображений. Для этого берётся ширина и высота оригинального изображения, а затем меньшая сторона изображения приравнивается к 400 (константа MIN_SIZE), а бóльшая пропорционально соответствующей стороне оригинального изображения. Или обе стороны приравниваются к 400, если изображение квадратное. Самое интересное происходит в этих строках:

В первой строке создаётся объект уменьшенного изображения, а во второй — записывается в файл.

Для запуска кода создаём класс Main:

Здесь создаём объект класса Resizer и вызываем его метод resize().

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

В структуре проекта появится папка images_previews. Если нужно добавить новую категорию или изображения в существующие категории — просто добавляем их в папку images и запускаем код ещё раз. Обработаны будут только новые файлы. Для удаления файла или категории удалять нужно из обеих папок.

Теперь напишем тесты для проверки результатов работы программы. Добавляем новый класс ImagesTests в test/java/com.illuzor.lesson.resizer:

Класс содержит два метода. testFilesExistence () проверяет, что для каждого файла в images есть соответствующий файл в images_previews. Метод testPreviewsSizes() проверяет размеры изображений. Размер меньшей стороны должен быть 399 или 400, а большей — больше или равен 399. Откуда взялось число 399, если мы задавали 400? Где-то в библиотеке imgscalr иногда получается погрешность и минимальный размер становится равным 399. Для нас это не критично.

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

С данными всё, переходим к серверу.

Сервер

Данные нужно где-то хранить и как-то отдавать их клиентскому приложению. Для этого нужен серверный код и хостинг. Вариантов с хостингом множество: можно использовать платный PHP хостинг, настроить VPS/VDS или собственный домашний сервер. Мы пойдёт самым простым путём и воспользуемся бесплатным PHP хостингом. Стоит понимать, что бесплатный хостинг всегда имеет различные ограничения и не гарантирует бесперебойную работу.

Напишем серверный код на PHP. Можно воспользоваться любым текстовым редактором. Я для небольших проектов предпочитаю Atom или Notepad++. Код очень простой и короткий, поэтому подойдёт даже стандартный блокнот.

В папке Wallpapers/Server создаём папку src, а в ней файл categories.php:

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

Создаём второй файл под именем gallery.php:

В переменную $gallery записывается GET параметр gallery, в массив $images добавляются имена всех файлов категории и возвращаются в виде json массива. Если категория не существуют или параметр gallery отсутствует, возвращается сообщение об ошибке. Результатом будет json массив со строками:

Это весь серверный код. PHP — интерпретируемый язык, компилировать код не нужно, но запустить его просто так не получится, для этого нужен сервер с интерпретатором.

Также создадим файл robots.txt, это специальный файл с правилами для индексации поисковиками. Нам индексация не нужна, поэтому запретим её для всех поисковиков:

Теперь разберёмся с хостингом. Я рассмотрю бесплатный PHP хостинг 000webhost. Работа с любым другим хостингом будет схожей. Переходим на страницу регистрации 000webhost.com/free-website-sign-up. Вводим email, пароль и имя сайта, которое станет частью домена третьего уровня вида your_domain.000webhost.com:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Жмём Get Free Hosting и перемещаемся в личный кабинет, предварительно закрыв пару рекламных баннеров. Ждём прихода на email письма с подтверждением регистрации и подтверждаем регистрацию. Открываем страницу со списком сайтов и видим, что наш сайт уже запущен:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

В верхнем меню нажимаем Settings/General и попадаем на страницу настроек. Отключаем Sendmail и отображение ошибок:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Убеждаемся, что включен доступ по FTP:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Нужно загрузить PHP код и файлы изображений на сервер. Для этого можно воспользоваться любым FTP клиентом, например FileZilla. Запускаем FTP клиент и вводим данные из FTP details:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Нажимаем кнопку Quickconnect. После подключения в правой части появятся серверные директории. Открываем папку public_html и перетаскиваем из левой части (локальная файловая система) три файла из Wallpapers/Server/src и наши папки images и images_previews. Загрузка может занять некоторое время. Структура файлов на сервере после загрузки:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Проверить работу скриптов можно через браузер. Для этого нужно к адресу сайта дописать /categories.php или /gallery.php. Адрес сайта можно найти на странице со списком сайтов. Я буду использовать свой адрес, а вы подменяйте его на свой.

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

При каждом обновлении страницы значения preview будут разными.

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Нужно добавить GET параметр. Обязательно, чтобы его значение было именем одной из категорий (названием одной из папок). Открываем wallpapers.illuzor.com/gallery.php?gallery=Earth и видим список имён файлов соответствующей категории:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

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

Небольшое отступление. Клиент не может и не должен знать, на чём написан сервер и как он работает. Тот же самый сервер можно было бы написать на любом другом языке: C++, Java, Kotlin, Ruby, Python… Всё, что должен знать клиент: на какие адреса отправлять запросы, как эти запросы должны выглядеть и в каком виде приходят ответы. Также можно написать клиентское приложение для IOS, Windows/Linux/MacOS или Web с тем же самым сервером без каких-либо изменений.

Клиент

Самая большая и сложная часть — клиентское приложение для Android. Урок разбит на 7 частей, для каждой из которых есть коммит в репозитории. Каждый коммит можно изучить на github или локально в склонированном репозитории. Это экспериментальный формат, не знаю, насколько удачный. Для работы понадобится Android Studio версии 3.2 или новее.

01) Создание и настройка проекта

Запускаем Android Studio и создаём новый проект. В качестве Project location указываем папку Wallpapers/Client и убеждаемся, что включена поддержка Kotlin:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Жмём Finish и ждём сборки gradle.

Возьмём прицел на будущее и перейдём на androidx. Возможно, следующие версии Android Studio будут сразу создавать проекты с androidx. Если видите в файле build.gradle в dependencies пакет androidx.appcompat:appcompat, пропустите этот шаг. Если же там com.android.support:appcompat-v7, выбираем в верхнем меню Refactor/ Migrate to AndroidX. Появится панель Refactoring Preview:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Жмём Do Refactor и ждём.

Открываем build.gradle уровня проекта (build.gradle Project: Client), добавляем список версий библиотек и репозиторий jitpack:

В build.gradle уровня модуля приложения (build.gradle Module: app) добавляем kotlin-kapt плагин и нужные библиотеки в dependencies:

Список сторонних библиотек в проекте:

В файле gradle-wrapper.properties обновляем версию gradle до 4.10.1:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Сверху выскочит напоминание о необходимости синхронизации проекта. Нажимаем Sync Now и ждём.

02) Ресурсы

Добавим необходимые ресурсы.

В структуре проекта находим файл res/values/strings.xml и добавляем строки:

Строку app_name оставляем на месте. Открываем файл res/values/colors.xml и добавляем один новый цвет blackTextColor:

В файле res/values/styles.xml меняем тему с Theme.AppCompat.Light.DarkActionBar на Theme.AppCompat.Light.NoActionBar:

В поиск вводим «error» и выбираем иконку error:

Нажимаем Ok, меняем имя на ic_error:

Нажимаем Next и Finish. То же самое повторяем с ic_refresh, ic_save и ic_share. Добавляем в drawable файл placeholder.png, он будет индикатором для незагруженных изображений. В итоге каталог drawable содержит 4 иконки и одно png изображение (вдобавок к двум уже существующим файлам):

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Настроим заодно манифест (app/manifest/AndroidManifest.xml). Нужно добавить три разрешения (интернет, запись во внешнее хранилище и установка обоев):

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

В application меняем значение параметра android:allowBackup с true на false. Итоговый вид манифеста:

03) Базовые и вспомогательные классы

Создадим заранее все пакеты:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Это класс для Glide Generated API, нам оно нужно для возможности использовать плейсхолдер.

В пакете extensions создаём файл (не класс) toast.kt:

Это два расширения для Activity и Fragment для упрощённого показа тоста.

В тот же пакет добавляем файл async.kt:

Это файл содержит две функции: runInBackground() для запуска кода в фоновом потоке и runInMainThread() для запуска кода в UI потоке. В каждую из функций нужно передать лямбду без параметров и без возвращаемого значения.

В пакете model создаём класс Category:

Это data класс для представления категории (список которых возвращает categories.php), то есть pojo класс.

Для Retrofit нужно создать интерфейс с описанием запросов к серверу. В пакете api создаём интерфейс WallpapersApi:

Интерфейс содержит два метода: categories () делает запрос на адрес categories.php и возвращает Call со списком категорий (pojo объектов). Второй метод gallery() запрашивает адрес gallery.php и требует аргумент galleryName, который будет передан в качестве get параметра, а возвращает Call со списком строк — имён файлов выбранной галереи.

В этом же пакете создаём файл api.kt:

Строковая константа BASE_URL содержит базовый адрес сервера. Замените адрес на свой (или не заменяйте и оставьте мой). Переменная api — объект WallpapersApi, через который будут осуществляться запросы к серверу. Обратите внимание на строку .addConverterFactory(GsonConverterFactory.create()). Здесь билдеру передаётся GsonConverterFactory. Это один из конвертеров для retrofit, который под капотом будет превращать json строки в Java объекты. Чтобы не воспринимать это, как магию, будет полезно посмотреть, как работает Gson сам по себе.

В пакет ui добавляем класс SquareConstraintLayout:

Это класс расширяет ConstraintLayout и переопределяет метод onMeasure. В super.onMeasure() в качество обоих параметров передаётся width, таким образом ширина всегда будет равна высоте, то есть лайаут будет квадратным. Нам он нужен для элементов списков с превью.

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Макет состоит из кругового прогресс-бара и TextView для отображения текста сообщения.

В пакет ui добавляем класс ProgressDialog:

Свойство title задаётся извне, в методе onCreateDialog() выводится в tv_title и затем метод возвращает диалог.

Теперь перетаскиваем класс MainActivity в пакет screens и переименовываем(Shift+F6) в AbstractActivity. Этот класс будет базовым для всех(трёх) наших активити. Класс должен быть абстрактным. Для этого добавляем ключевое слово abstract перед определением класс (перед ключевым словом class). Рассмотрим код:

Абстрактное поле layoutId — id макета для активити. Абстрактный метод getFragment() возвращает фрагмент, который будет отображён в активити. В переопределённом методе onCreate() задаётся contentView. Далее проверяется, есть ли фрагмент во fragmenManager:

Если фрагмент не найден(равен null), получаем его через метод getFragment и добавляется во fragmentManager:

Макетов для активити пока что нет, поэтому идентификатор R.id.container будет подсвечен линтом, это не страшно, позже мы добавим для всех активити макеты, в каждом из которых будет container.

Через метод setToolbar() настраивается тулбар и включается кнопка up (стрелка на тулбаре).

В переопределённом методе onOptionsItemSelected() проверяется — если нажата кнопка up, завершаем активити.

Осталось удалить AbstractActivity из манифеста:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Теперь манифест выглядит так:

На этом с подготовкой всё. Можно переходить к созданию экранов приложения.

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

04) Экран категорий

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Экран категорий представляет собой список категорий в две колонки. Каждый элемент списка состоит из изображения и текста с названием категории. Что нужно для для реализации такой функциональности? Макеты для активити и фрагмента, классы для активити и фрагмента, RecyclerView для отображения списка и адаптер для него, а также макет для элемента списка. Данные нужно загрузить с сервера и в виде списка категорий (List ) передать в адаптер для RecyclerView. Для инкапсуляции загрузки данных через Retrofit будет использоваться библиотека ViewModel, кроме этого она поможет легко пережить смену конфигурации, например поворот экрана. Для загрузки изображений воспользуемся библиотекой Glide.

Начнём с вёрстки макетов. Добавляем в res/layout файл activity_fragment.xml:

Это макет для активити. Он содержит только FrameLayout, который будет контейнером для фрагмента.

Добавляем ещё один файл fragment_list.xml:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Добавляем последний макет item_category.xml:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Это макет для элемента списка (RecyclerView). Обратите внимание на корневой элемент, это SqureConstraintLayout, класс которого мы создавали ранее. Макет содержит: ImageView (iv_preview) для превью изображения, View — подложка для текста и TextView(tv_title) для отображения названия категории.

Теперь к коду. Займёмся адаптером. В первую очередь для адаптера нужен ViewHolder. Создаём в пакете adapters новый класс CategoryViewHolder:

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

Создаём новый класс AbstractAdapter:

Создаём класс CategoriesAdapter:

Теперь подумаем над загрузкой данных. С сервера нужно загрузить список категорий, для этого у нас есть объект WallpapersApi — переменная api в файле api.kt. Применим библиотеку ViewModel. Саму загрузку мы инкапсулируем в отдельном классе ViewModelCategories, расширяющем androidx.lifecycle.ViewModel. Объект такого класса можно получить через androidx.lifecycle.ViewModelProviders примерно таким кодом:

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

Создадим в пакете model базовый класс ViewModelBase:

В первую очередь объявляется enum State. Это список возможных состояний:

Для отражения текущего состояния есть свойство state с protected сеттером. Это значит, что получить переменную можно извне, но изменить только из текущего или унаследованного класса. Поле loadListener — слушатель загрузки, лямбда без параметров, которая ничего не возвращает. А также метод setListener() для установки этого слушателя.

Теперь создаём класс ViewModelCategories, унаследованный от ViewModelBase:

Осталось создать только фрагмент и активити. Сначала создадим абстрактный фрагмент, который упростит отображение прогресса. Создаём в пакете screens класс AbstractFragment:

Поле contentView у разных фрагментов будет разным, его нужно будет задать вручную для каждого унаследованного фрагмента. Абстрактное поле layoutId, которое нужно будет переопределить так же, как в AbstractActivity. В переопределённом методе onCreateView() разворачивается и возвращается View фрагмента. Три метода: showProgress() и showContent() скрывают и показывают нужные view, а метод showError, кроме этого устанавливает текст ошибки и обрабатывает клик по кнопке Retry — вызывает переданную лямбду.

Теперь реализация фрагмента для категорий. Создаём новый класс CategoriesFragment, унаследованный от AbstractFragment():

Здесь переопределяется поле layoutId, и есть ещё два поля: adapter(CategoriesAdapter), который мы реализовали ранее и model(ViewModelCategories), который у нас тоже есть. В методе onCreate() получаем объект класса ViewModelCategories:

В методе onActivityCreated задаём contentView, назначаем адаптеру layoutManager и adapter и вызывает метод checkData(), который пуст. Нужно его реализовать:

В этом методе мы проверяем, в каком состоянии находится model. Если он только что создан (CREATED), показываем индикатор загрузки — showProgress(), вешаем на model слушатель, в котором вызывается сам метод checkData() и запускаем загрузку вызовом model.load(). Если загрузка в процессе (PROGRESS), показываем индикатор загрузки и вешаем слушатель. Если произошла ошибка (ERROR), показываем ошибку со слушателем, который делает то же самое, что и при CREATED. И самое главное, если данные загружены(LOADED), отдаём их в адаптер отсортированными по имени, показываем контент (RecyclerView) и вешаем слушатель на адаптер. Он, пока что останется пустым.

В самом начале метода проверяем: если view равно null, завершаем метод. Это нужно для избежания одной ошибки. Так как model переживает смену конфигурации, может случиться так, что загрузка может завершиться между уничтожением старого Activity, но перед созданием нового. Тогда сработает слушатель и случится NullPointerException, так как никакие View ещё не существуют, а мы к ним обращаемся через методы showContent()/showProgress()/showError(). На современных устройствах эта ошибка маловероятна, но на старых с медленным интернетом она вполне реальна.

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Нажимаем Finish. Активити автоматически пропишется в манифесте и будет стартовой. Открываем созданный класс CategoriesActivity, наследуем его от AbstractActivity вместо AppCompatActivity и удаляем метод onCreate. Всё, что нужно сделать — переопределить свойство layoutId и метод getFragment():

Можно запустить(Shift+F10) приложение на устройстве или на эмуляторе и посмотреть, что получилось. На экране появятся две колонки белых превью, которые быстро заменяются загруженными изображениями. При каждом запуске превью будут разными. Список можно прокрутить, но нажатие на элементы, пока что, не обрабатываются. Чтобы увидеть сообщение об ошибке, нужно выключить wifi и мобильный интернет и перезапустить приложение. Если теперь включить интернет и нажать на кнопку Retry, всё заработает, как и должно. Если повернуть телефон во время загрузки, она не прервётся, благодаря ViewModel. Если перевернуть телефон, когда данные уже загружены, загрузка не начнётся заново, так как данные остаются во ViewModel.

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

05) Экран категории

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

На этом экране будет отображаться список превью изображений из выбранной категории. Для его создания нужно примерно то же самое, что для экрана галереи — классы для активити и фрагмента, класс адаптера, класс ViewModel. Будет немного попроще, так как все базовые классы у нас уже есть. Макет для фрагмента будет использовать тот же самый, а для активити и элемента списка нужны новые.

Создаём макет для активити с именем activity_with_toolbar.xml:

От макета activity_fragment.xml он отличается только наличием тулбара.

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

И ещё один макет item_gallery.xml для элемента списка:

Здесь всё то же самое, что в item_category.xml, но без TextView, то есть SquareConstraintLayout с ImageView для превью.

Переходим к адаптеру. Создаём в пакете adapters ViewHolder класс под названием GalleryViewHolder:

Код класса полностью аналогичен коду CategoryViewHolder, за исключением отсутствия поля tvTitle и метода setTitle(). Дубликаты кода, это плохо. Можно унаследовать CategoryViewHolder от GalleryViewHolder и удалить дублирующийся код. Можете сделать это самостоятельно.

Создаём в пакете adapters класс GalleryAdapter:

Создаём ViewModel — класс ViewModelGallery в пакете model:

В пакете screen создаём класс GalleryFragment:

Основное отличие этого класса от CategoriesFragment в том, что появилось поле category — это строковая переменная, которая берётся из аргументов. О том, откуда она взялась скоро узнаем. Эта переменная передаётся параметром в model.load().

Осталось создать активити:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Открываем код класса GalleryActivity и меняем его на следующий:

В метод setToolbar() передаётся id тулбара и строка с id «category», которую берётся из интента. В переопределённом методе getFragment () создаём переменную Bundle и добавляем туда ту же строку «category», создаём фрагмент, устанавливаем наш Bundle в качестве arguments фрагмента и возвращаем фрагмент. Откуда в интенте взялась строка «category»? Открываем класс CategoriesFragment и дописываем код в методе checkData() в блоке LOADED:

Весь код обновлённого класса CategoriesFragment.

Экран галереи готов. Можно запускать приложение.

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

06) Экран изображения. Часть первая: загрузка файла и создание меню

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Это последний экран, на котором будет отображено полноразмерное изображение с возможностью увеличения и уменьшения жестами. В тулбаре будут три кнопки: установить обои, поделиться изображением, сохранить изображение в галерею. Для реализации нам понадобится загрузить файл полноразмерного изображения с сервера на устройство. Этот файл можно будет легко загрузить в ImageView (точнее в PhotoView, который расширяет ImageView) через Glide, его можно будет установить на обои, поделиться им и сохранить в галерею.

Начнём с вёрстки. Создаём файл fragment_wallpaper.xml:

Просто скопируйте код из fragment_list.xml и замените RecyclerView на PhotoView.

Открываем интерфейс WallpapersApi из пакета api и добавляем метод downloadFile():

Метод принимает строковый параметр fileUrl с аннотацией @ Url. Этот параметр будет преобразован в относительный путь. Метод возвращает Call с ResponseBody, из которого можно будет достать InputStream с байтами файла.

Создаём в пакете model класс ViewModelWallpaper:

и записываем его в новый FileOutputStream с файлом:

Метод copyTo — это расширение из стандартной библиотеки Kotlin. Когда сохранение файла завершится, вызываем функцию runInMainThread(), которая выполнит код в UI потоке. В её лямбде присваиваем свойству state значение LOADED и вызываем слушатель.

Также есть переопределённый метод onCleared(). Он будет вызван автоматически, когда погибнет фрагмент, к которому привязан ViewModel. Если загрузка файла началась, но ещё не закончилась, то есть файл загружен частично, этот файл будет удалён, так как частично загруженный файл нам не нужен.

Создадим в пакете screens класс WallpaperFragment и унаследуем его от AbstractFragment:

Пусть, пока что, будет пустым.

Создадим в том же пакете новую активити:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Тут всё аналогично GalleryActivity, кроме того, что в Bundle добавляются две строки — «filename» и «category».

Открываем класс GalleryFragment и в методе checkData() дописываем код в блоке LOADED:

Займёмся меню для WallpaperFragment. Для этого создаём директорию menu в res и добавляем туда файл menu_wallpaper.xml:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Меню содержит три пункта: для установки обоев, для шаринга изображения и для сохранения изображения в галерею.

Открываем класс WallpaperFragment. Дальше работать будет только с ним. Надо подумать над загрузкой и хранением файлов изображений. Мы будем загружать файлы в директорию кэша (context.cacheDir), а точнее, в отдельную поддиректорию с именем wallpapers. Файлы на устройстве занимают довольно много места, поэтому надо придумать простой кэш. Сделаем так, чтобы после накопления некоторого количества файлов, все они удалялись из директории wallpapers. Приводим класс WallpaperFragment к следующему виду:

В начале объявляется несколько полей. loaded для понимания, загружен файл или нет. relativeUrl — относительный путь для загрузки файла изображения. model — собственно ViewModelWallpaper. imageFile — файл изображения. CACHE_SIZE — размер кэша(количество файлов).

В методе onCreate() включаем меню через setHasOptionsMenu(), получаем объект ViewModelWallpaper, достаём filename и category из аргументов, инициализируем relativeUrl и передаём в метод createFile() имя файла, состоящее из категории и имени файла с сервера.

В методе createFile() инициализируем файл и проверяем, существует ли он. Если существует, просто прерываем метод через return. Проверяем существование каталога wallpapers и равно ли количество файлов в нём CACHE_SIZE. Если да, удаляем все файлы, если нет, создаём каталог wallpapers.

Добавляем ещё три метода:

В методе loadFileToImageView() происходит загрузка изображения из файла в pv_wallpaper, то есть в PhotoView. Вначале показываем контент через showContent(), затем грузим изображение и в конце присваиваем переменной loaded значение true. В onActivityCreated() определяем contentView, затем проверяем — если model.state не равен PROGRESS и файл существует, загружаем файл, иначе вызываем метод checkData (), который в целом аналогичен методам в двух других фрагментах.

Добавим меню. Ещё несколько методов:

Ссылка на весь код класса.

Запускаем приложение и смотрим, что получилось.

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

07) Экран изображения. Часть вторая: сохранить, поделиться, установить на обои.

Начнём с самого простого — с сохранения изображения в галерею, то есть в каталог Pictures на устройстве. Для этого сначала нужно запросить разрешение на запись (WRITE_EXTERNAL_STORAGE) для Android M(23) и старше.

В начале класса объявляем новое поле REQUEST_STORAGE_PERMISSION_CODE:

Это код для запроса разрешения.

Реализуем метод checkPermissionForImageSave() и добавляем два новых:

В методе checkPermissionForImageSave() проверяем, если версия ниже, чем M(23) или разрешение WRITE_EXTERNAL_STORAGE подтверждено, вызываем saveImageToGallery (), иначе запрашиваем разрешение WRITE_EXTERNAL_STORAGE. В onRequestPermissionsResult() проверяем, дал ли пользователь разрешение. Если да, сохраняем изображение, иначе показываем тост с сообщением о необходимости дать разрешение. И в методе saveImageToGallery () сохраняем изображение. Сначала показываем ProgressDialog, затем в фоновом потоке сохраняем изображение через MediaStore. Когда сохранение завершится, закрываем диалог и выводим тост об удачном сохранении в ui потоке

Можно запустить и проверить. После сохранения изображение можно будет увидеть в приложении галереи.

Ссылка на весь код класса.

Для того, чтобы поделиться изображением и установить его на обои, нужен провайдер для доступа других приложений к файлам из кэша. В res создаём каталог xml и добавляем в него файл files.xml:

Здесь прописан путь к папке wallpapers в директории кэша (cache-path).

В манифесте прописываем провайдер в ноде application:

Ссылка на весь код манифеста.

Возвращаемся в класс WallpaperFragment и добавляем несколько полей класса:

SHARING_REQUEST_CODE и SETTING_REQUEST_CODE — коды для запуска соответствующих активити. Строка PROVIDER_AUTHORITY нужна для идентификации провайдера и должна совпадать с android:authorities из провайдера в манифесте. imageFileUri — Uri для файла imageFile, переменная объявлена, как ленивая, так как она в большинстве случаев не понадобится.

Реализуем метод shareWallpaper():

Добавляем метод onActivityResult:

resultCode нам не интересен. Важно только одно — если requestCode равен SHARING_REQUEST_CODE или SETTING_REQUEST_CODE, отменяем разрешение на доступ к Uri.

Ссылка на весь код класса.

Можно снова запустить приложение и проверить.

Самое последнее, что осталось — реализовать метод setWallpaper():

Показываем диалог, в фоновом потоке устанавливаем обои через WallpaperManager, в ui потоке закрываем диалог и показываем тост с сообщением об удачной установке. Можно запустить и проверить, как это работает.

Вроде, всё готово, но нет. Такой способ не очень хорош, лучше оставить его на крайний случай, а установку обоев делегировать через неявный интент кому-нибудь, кто справится с этим лучше. Меняем код метода setWallpaper():

Объявляем интент на установку обоев, проверяем, есть ли в системе активити, которые этот интент могут обработать. Если нет, запускаем код из прошлой версии метода setWallpaper(). Если же такие активити есть, донастраиваем интент, раздаём всем активити разрешение на доступ к Uri и в конце запускаем активити через startActivityForResult().

Ссылка на весь код класса.

Готово. Запускаем приложение и смотрим на результат.

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Задания

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

Кэширование на сервере

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

Кэширование в приложении

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

Внешний вид приложения

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

Адаптация для горизонтального режима и планшетов

Если повернуть телефон горизонтально, мы увидим следующее:

как создать сервер для мобильного приложения. Смотреть фото как создать сервер для мобильного приложения. Смотреть картинку как создать сервер для мобильного приложения. Картинка про как создать сервер для мобильного приложения. Фото как создать сервер для мобильного приложения

Выглядит не очень хорошо. Было бы лучше отобразить список экрана категорий в виде трёх колонок, а список экрана галереи — в виде двух. На планшетах всё ещё хуже. Исправить эту проблему можно с помощью GridLayoutManager для RecyclerView. Для определения, когда сколько колонок отображать есть, как минимум, два способа:

Перелистывание обоев

При открытом WallpaperActivity было бы удобно листать следующие/предыдущие изображение свайпами влево/вправо. Сделать это можно с помощью ViewPager. Есть один не очевидный баг при использовании PhotoView совместно с ViewPager. Если столкнётесь с ним, постарайтесь исправить самостоятельно, если не получится, свяжитесь со мной, я подскажу.

Заключение

И напоследок небольшая просьба. Вы можете без ограничений использоваться мои ссылки с доменом wallpapers.illuzor.com для обучения, но я прошу не публиковать приложения с этими ссылками.

На этом всё, спасибо за внимание и интерес к материалу.

Источник

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

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