Поговорить об архитектуре всегда интересно, в особенности когда ты ее используешь повсеместно во всех своих приложениях. Сейчас очень популярно и модно везде использовать MVVM архитектуру которую я описывал тут буквально недавно.
Сегодня я хочу поговорить про такой паттерн который используется в большинстве современных приложений, который называется MVP, на его замену пришел уже названный ранее MVVM который является более простым и понятным паттерном, но MVP в современной разработке используется везде где можно и нельзя, и так же она имеет применение в мобильной разработке, которую я так сильно люблю.
Если кратко что такое MVP то вот вам развертка:
— Model — уровень данных. Все называют его как «уровень бизнес логики», но для меня он очень абстрактный и в большинстве случаев его можно интерпретировать как угодно, но только не так что бы было понятно. Поэтому в своих приложениях я называю его Repository и он работает с базой данных или сервером или какой-то внутреней структурой данных.
— View — уровень отображения. Это любая Activity, Fragment или Custom View котоые описывают работу с объектами отображения (TextView, RecyclerView и т.д.). Напомню, что изначально все Android приложения подчинены структуре MVP, где Controller это Activity или Fragment.
— Presenter — прослойка между View и Model. View передаёт ему происходящие события, презентер обрабатывает их, при необходимости обращается к Model и возращает View данные на отрисовку.
Что же мы из этого всего вынесли полезного?
— View — знает о Presenter. Отображает все что возвращает презентер;
— Presenter — знает о View и Model (Repository). Берет данные из модели и отдает во вью;
— Model (Repository) — сама по себе. Она у нас получает данные и отдает тому кто попросит;
Теперь же перейдем к практической части. У нас нужно провести небольшую подготовку прежде чем реализовывать сам паттерн в нашем проекте. По этому давайте подключим библиотеки, создадим модели и подключим работу с сервером.
app/build.gradle
Подключаем Retrofit, RecyclerView и appcompat для работы с сервером, списками и остальными важными частями android sdk.
Дальше по стандарту описываем работу с сервером как это уже было в сотне статей которые я тут описывал, все будет аналогично десятку примеров которые тут были.
PostModel.kt
Подготавливаем модель для обработки данных с сервера, по традиции получать будем тайтл и описание, и будем потом его отображать в списке.
API.kt
Далее описываем запрос к серверу, в нашем случае мы будем получать список постов, в нашу модельку которую создали выше.
RestClient.kt
Дальше создаем класс который абстрагирует работу с сервером, используя интерфейс API, в котором мы описали сам запрос.
Далее, после того как мы описали работу с сервером, нам нужно описать интерфейсы которые будут иметь методы с которыми мы в дальнейшем будем взаимодействовать между объектами самого MVP.
PostRepository.kt
Даный интерфейс говорит о том что в нашем имплементации данного интерфейса будет содержать один метод, который будет получать посты с сервера.
PostsRepositoryImpl.kt
Здесь мы создали класс и заимплементили наш интерфейс, после этого создали метод который описывает работу с сервером, сделали вызов RestClient'a и в onResponse отправляем колбек на подписавшегося на тот коллбек класса, в нашем случае это будет Presenter. Так же в конструкторе мы говорим о том что каждый класс который будет создавать инстанс данного репозитория должен подписаться на коллбек для получения списка постов.
PostPresenter.kt
В данном интерфейсе мы будем обратаывать клик по айтему в списке. И так же в конструкторе будем подгружать данные с сервера.
PostPresenterImpl.kt
В конструкторе мы передаем View, потому что наш активити должен содержать имлемент к View, а презентер будет обращаться к этим элементам View и работать с ними. Так же в init методе мы создаем объект Repository и сразу вызываем метод getPosts что бы получить данные с сервера по запуску приложения. И так же на коллбек showPosts, отображаем посты во View (активити) и по клику onItemWasClicked отправляем клик в View (активити).
PostsView.kt
Вот так будут выглядеть три наших интерфейса которые будут взаимодействовать между друг другом. PostsRepository будет получать инфу из сервера и будет передавать ее в PostsPresenter, а PostsView будет отображать с помощью Presenter'a все это безобразие.
Так же нам еще осталось создать адаптер с холдером для отображения списка, опускать уже эту информацию не буду, и нарисую тут как будет выглядеть эти два класса.
PostViewHolder.kt
В айтеме у нас будет два поля, одно будет как тайтл, второе как дескрипшн, собственно что мы в этом холдере и делаем, берем из данной нам модели данные и отображаем в этих текстовых полях. Так же говорим что весь айтем будет кликабельный и мы по к лику передаем позицию в списке.
PostRecyclerAdapter.kt
Стандартно рисуем адаптер, инициализируем холдер, передаем туда список полученый с сервера и лисенер который будет контролировать клики по списку.
item_posts.xml
Вот так будет выглядеть айтем списка. Два текстовых поля с небольшими отступами.
Далее нам нужно заимплементировать PostsView в нашей MainActivity и подписаться на коллбеки которые будут возвращать нам или респонс или клик по айтему из презентера.
MainActivity.kt
В onCreate мы создали инстанс нашего Presenter'a и подписались на колбеки, дальше создали два метода которые у нас будут отображать список (showPosts) и делать какие-то действия по клику на айтем (onPostClick). Собственно эти два метода которые мы описали в интерфейсе PostsView.
activity_main.xml
Наша активити будет в себе содержать только список в котором сразу будет прописан леяут менеджер для удобства что бы не требовалось это делать в коде.
AndroidManifest.xml
Так же нужно еще прописать работу с интернетом в манифесте, и собственно на этом можно запускать и смотреть как работает наше идеальное приложение.
В активити теперь минимум кода, все скрыто под капотом нашей архитектуры. Но при этом что бы добавить что-то новое теперь совершенно не составит труда, добавить например новый запрос в Repository очень просто — создаем просто еще один метод в интерфейсе, и потом описываем его работу в имплементе данного интерфейса, так же и с остальным, все что нам нунжно сперва создаем в интерфейсе, потом имплементим в классах которые это требуют. Все очень гибко и красиво.
Исходники:
GitHub
Если кратко что такое MVP то вот вам развертка:
— Model — уровень данных. Все называют его как «уровень бизнес логики», но для меня он очень абстрактный и в большинстве случаев его можно интерпретировать как угодно, но только не так что бы было понятно. Поэтому в своих приложениях я называю его Repository и он работает с базой данных или сервером или какой-то внутреней структурой данных.
— View — уровень отображения. Это любая Activity, Fragment или Custom View котоые описывают работу с объектами отображения (TextView, RecyclerView и т.д.). Напомню, что изначально все Android приложения подчинены структуре MVP, где Controller это Activity или Fragment.
— Presenter — прослойка между View и Model. View передаёт ему происходящие события, презентер обрабатывает их, при необходимости обращается к Model и возращает View данные на отрисовку.
Что же мы из этого всего вынесли полезного?
— View — знает о Presenter. Отображает все что возвращает презентер;
— Presenter — знает о View и Model (Repository). Берет данные из модели и отдает во вью;
— Model (Repository) — сама по себе. Она у нас получает данные и отдает тому кто попросит;
Теперь же перейдем к практической части. У нас нужно провести небольшую подготовку прежде чем реализовывать сам паттерн в нашем проекте. По этому давайте подключим библиотеки, создадим модели и подключим работу с сервером.
app/build.gradle
Подключаем Retrofit, RecyclerView и appcompat для работы с сервером, списками и остальными важными частями android sdk.
Дальше по стандарту описываем работу с сервером как это уже было в сотне статей которые я тут описывал, все будет аналогично десятку примеров которые тут были.
PostModel.kt
Подготавливаем модель для обработки данных с сервера, по традиции получать будем тайтл и описание, и будем потом его отображать в списке.
API.kt
Далее описываем запрос к серверу, в нашем случае мы будем получать список постов, в нашу модельку которую создали выше.
RestClient.kt
Дальше создаем класс который абстрагирует работу с сервером, используя интерфейс API, в котором мы описали сам запрос.
Далее, после того как мы описали работу с сервером, нам нужно описать интерфейсы которые будут иметь методы с которыми мы в дальнейшем будем взаимодействовать между объектами самого MVP.
PostRepository.kt
Даный интерфейс говорит о том что в нашем имплементации данного интерфейса будет содержать один метод, который будет получать посты с сервера.
PostsRepositoryImpl.kt
Здесь мы создали класс и заимплементили наш интерфейс, после этого создали метод который описывает работу с сервером, сделали вызов RestClient'a и в onResponse отправляем колбек на подписавшегося на тот коллбек класса, в нашем случае это будет Presenter. Так же в конструкторе мы говорим о том что каждый класс который будет создавать инстанс данного репозитория должен подписаться на коллбек для получения списка постов.
PostPresenter.kt
В данном интерфейсе мы будем обратаывать клик по айтему в списке. И так же в конструкторе будем подгружать данные с сервера.
PostPresenterImpl.kt
В конструкторе мы передаем View, потому что наш активити должен содержать имлемент к View, а презентер будет обращаться к этим элементам View и работать с ними. Так же в init методе мы создаем объект Repository и сразу вызываем метод getPosts что бы получить данные с сервера по запуску приложения. И так же на коллбек showPosts, отображаем посты во View (активити) и по клику onItemWasClicked отправляем клик в View (активити).
PostsView.kt
Вот так будут выглядеть три наших интерфейса которые будут взаимодействовать между друг другом. PostsRepository будет получать инфу из сервера и будет передавать ее в PostsPresenter, а PostsView будет отображать с помощью Presenter'a все это безобразие.
Так же нам еще осталось создать адаптер с холдером для отображения списка, опускать уже эту информацию не буду, и нарисую тут как будет выглядеть эти два класса.
PostViewHolder.kt
В айтеме у нас будет два поля, одно будет как тайтл, второе как дескрипшн, собственно что мы в этом холдере и делаем, берем из данной нам модели данные и отображаем в этих текстовых полях. Так же говорим что весь айтем будет кликабельный и мы по к лику передаем позицию в списке.
PostRecyclerAdapter.kt
Стандартно рисуем адаптер, инициализируем холдер, передаем туда список полученый с сервера и лисенер который будет контролировать клики по списку.
item_posts.xml
Вот так будет выглядеть айтем списка. Два текстовых поля с небольшими отступами.
Далее нам нужно заимплементировать PostsView в нашей MainActivity и подписаться на коллбеки которые будут возвращать нам или респонс или клик по айтему из презентера.
MainActivity.kt
В onCreate мы создали инстанс нашего Presenter'a и подписались на колбеки, дальше создали два метода которые у нас будут отображать список (showPosts) и делать какие-то действия по клику на айтем (onPostClick). Собственно эти два метода которые мы описали в интерфейсе PostsView.
activity_main.xml
Наша активити будет в себе содержать только список в котором сразу будет прописан леяут менеджер для удобства что бы не требовалось это делать в коде.
AndroidManifest.xml
Так же нужно еще прописать работу с интернетом в манифесте, и собственно на этом можно запускать и смотреть как работает наше идеальное приложение.
В активити теперь минимум кода, все скрыто под капотом нашей архитектуры. Но при этом что бы добавить что-то новое теперь совершенно не составит труда, добавить например новый запрос в Repository очень просто — создаем просто еще один метод в интерфейсе, и потом описываем его работу в имплементе данного интерфейса, так же и с остальным, все что нам нунжно сперва создаем в интерфейсе, потом имплементим в классах которые это требуют. Все очень гибко и красиво.
Исходники:
GitHub
Nice blog on mvp i have provided a tutorial on latest architecture for apps
ОтветитьУдалитьhttp://www.androidcoding.in/2020/05/03/mvvm-architecture-beginners-guide-android-coding/