MVP в Android приложении (Часть 3).

Oleg Skidan
5 min readNov 20, 2016

--

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

В этой части мы рассмотрим реализацию данного паттерна с привязкой к библиотекам Retrofit и RxAndroid. В качестве примера нам послужит приложение для мониторинга землетрясений. Для этих целей воспользуемся API от USGS.

Немного опишу, в чём заключается суть идеи.

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

Документация Android для таких запросов предлагает использовать классы HttpUrlConnection (для работы по сети), и AsyncTask или Loader для обработки запросов вне основного потока приложения и обновления информации на экране.

Я не буду останавливаться на том, чем именно эти классы не устраивают разработчиков, так как это не является основной темой статьи. Скажу лишь, что удобнее работать с готовыми библиотеками от Square для сетевых запросов (как правило, это OkHttp и Retrofit) и RxAndroid (для реактивного программирования), который представляет из себя набор идей: паттерн “Наблюдатель” и функциональное программирование. Детальные ссылки с описанием находятся в конце статьи.

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

Первым делом нам потребуется подключить необходимые библиотеки в нашем gradle файле. Хочется отметить, что RxAndroid требует подключения RxJava. А также для удобства подключены лямбды через библиотеку retrolambda.

Структура проекта будет такой же, как и во второй части. Сам проект и его структура:

Приложение представляет из себя всего 1 экран, который отображает топ 10 землетрясений за последнее время.

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

Прежде чем создавать сервис для работы с запросами, нам потребуется представить json данные (которые мы получаем по ссылке) в качестве наших классов. Именно для этого нам и требуется gson, который помогает сериализовать java классы в json данные и десериализовать их.

Для запросов мы будем использовать URL, который возвращает нам json данные. Чтобы представить их в качестве наших java классов, мы можем воспользоваться готовыми инструментами или написать такие классы вручную. Я же пользуюсь следующим ресурсом — http://www.jsonschema2pojo.org

Как это выглядит создание POJO из JSON данных

После генерации наших POJO файлов, мы можем или вручную скопировать их в наш проект или же скачать.

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

Так как основная задача presenter-a — это запрашивать у model данные, значит нам понадобится класс, который эти данные подготавливает при вызове некоторого метода. Для этих целей нам послужит класс EarthquakeApi:

Здесь и далее, нужно учитывать, что практически каждый класс (во всех трёх слоях) имеет интерфейс.

Хочу отметить одно удобство. Retrofit из коробки уже умеет работать с Observable, поэтому именно его мы и будем возвращать. Более подробно об Observable можно прочитать в ссылках в конце статьи.

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

  1. Мы должны создать POJO для наших данных. Так как работа происходит с данными формата JSON, нам потребуется подключить GSON библиотеку.
  2. Нам нужно создать интерфейс, который потребуется для выполнения запросов через Retrofit.
  3. Для взаимодействия с моделью нам потребуется некоторая точка входа. Некоторые добавляют к её названию -Repository. Я же использую класс, в названии которого есть -API.

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

Этот интерфейс позволит нам обращаться к нашему экрану через Presenter.
Реализация экрана

Реализация экрана довольно тривиальная. Методы для обновления информации и, конечно же, стандартная точка, где создаётся Presenter. Хочу напомнить, что экран служит только для отображения информации. Саму же информацию мы будем получать от Presenter-a.

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

Сам Presenter содержит в себе ссылку на Model и на View, так как он является посредником между данными и отображением. Вот тут то мы и посмотрим на RxAndroid поближе.

Здесь фишка заключается в следующем. Когда мы запрашиваем у модели данные, мы получаем Observable, который выполняется только когда мы вызываем метод subscribe(). При этом, стоит помнить, что Presenter должен обновлять данные в представлении. А значит взаимодействовать с ним он должен через основной поток приложения. В то же время, при вызове метода мы работаем с сетью, а значит должны выполнять все запросы в отдельном потоке, дабы наше приложение не рухнуло с исключением NetworkOnMainThreadException.

Для этого в RxAndroid существуют Schedulers, которые позволяют делать выполнение запросов в отдельном потоке, а обработку данных и отправку их в представление — через главный поток. Эти два подхода представлены методами subscribeOn() и observeOn(). Метод subscribe() как раз и занимается тем, чтобы полученные данные отправить в представление, которое обновит свой список.

У некоторых может возникнуть вопрос, почему бы не обновить сам список или данные экрана через его Presenter. Здесь всё довольно просто — наш Presenter не должен знать ничего о самой системе классов Android-a.

Теперь посмотрим на всю цепочку связей и вызовов в примере:

  1. При запуске приложения у нас создаётся экземпляр Presenter-а, который вызывается для запроса данных.
  2. Presenter в свою очередь получает ссылку на вызывающее представление и создаёт экземпляр доступа к модели.
  3. Для получения Observable наш Presenter вызывает метод нашей модели.
  4. Наша модель создаёт запрос к серверу через Retrofit и возвращает Observable.
  5. Presenter подписывается на этот Observable и при получении результата обрабатывает его и отправляет в представление.
  6. Представление отображает результат в ListView.

На этом пример завершён. В следующей статье мы поговорим о тестировании приложений, написанных с использованием паттерна MVP.

Всех благ.

Ссылки на библиотеки и их Wiki:

RXJava: Source, Wiki.

RXAndroid: Source, Wiki.

Retrofit Source, Wiki.

P.S. Один из моих студентов любил собирать уроки, разбитые на части в один pdf файл. Удобно. Рекомендую тем, кому тяжело освоить информацию по статьям.

--

--