Как стать автором
Обновить

Построение Android приложений шаг за шагом, часть первая

Время на прочтение8 мин
Количество просмотров146K
Всего голосов 32: ↑27 и ↓5+22
Комментарии48

Комментарии 48

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

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

P.S. Есть канал по паттернам, где 90% обсуждений посвящено MVP, можно присоединяться :)
Спасибо за комментарий и канал по паттернам! Менеджмент подписки и использование лоадеров тема для отдельной статьи, везде есть свои плюсы и минусы)
НЛО прилетело и опубликовало эту надпись здесь
А аргументы? :-)
Поясните?
Чего минусите то человека? Дело говорит. Посмотрите на количество файлов и связность.
Ну, заявиться и сказать, что кг/ам (образно), — дело плевое.
А вот привести конкретную аргументацию на ресурсе, который посещают в том числе и новички, — силушки не хватило :)
НЛО прилетело и опубликовало эту надпись здесь
Нарисуете свою схему именно для этого примера?
Я не умею рисовать схемы (шутка) =) Но на словах: зачем три файла/класса для презентера? Зачем интерфейс Presenter (если там lifecycle callback методы, то и назовите его LifecycleCallbacks по аналогии с ActivityLifecycleCallbacks)? А абстрактный BasePresenter, чтобы от CompositeSubscription отписываться? Увеличение абстракции оправдано, если вы пишете какой-нибудь фреймворк или библиотеку. Или это делается потому что так написано в статьях по MVP? Задайте себе вопрос: как часто вам приходилось выкидывать один презентер и заменять его на другой? Мне, например, ни разу.
Что касается Model слоя: приложение вообще ничего не должно знать о сущностях DTO, DBO а так далее. Это все лучше вынести в, так называемый, Repository слой. В котором выполняются мапинги данных, принятия решений о том, откуда эти данные брать (из кэша, БД или сети) и так далее. Наружу торчит только Observable<List> getRepoList(String name);

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

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

А вот по сущностям в модели можно обсудить.
Вы предлагаете жёстко привязаться к модели данных.
Возьмём за пример модель RepositoryDTO — в реальности это большая модель с большим количеством полей.
В этом примере слою View надо всего лишь 4 поля. Для этого создаётся отдельный ViewObject — Repository(не путать с вашим паттерном) который содержит только нужные поля, тем самым абстрагируясь от RepositoryDTO и от модели вообще.
Можно предположить, что в будущем измениться апи, скажем c GitHub на GitLab.
В текущем примере нужно поменять маппер Model <->ViewObject. В вашем менять View.
Вы меня неправильно поняли. Я как раз об этом и говорил. Есть некоторые сущности, которые являются ViewObject, при этом откуда она была получена, нам абсолютно неважно. Получение же этого ViewObject логично вынести в слой, который я назвал Repository, роль которого в контексте статьи выполняет ApiInterface. Просто я предлагаю скрыть всю реализацию мапингов и прочих манипуляций внутри реализации ApiInterface и наружу выдавать уже готовые ViewObject модели. В статье же это делается на уровне презентера.
getRepoList() { 
    return retrofit.getRepoList().flatMap({Model -> ViewObject});
}
Я понял, можно, но это если View чётко соответсвует одной модели, а если нет?
Например, есть 2 Активити, которым нужна одна модель, но разные поля из неё т.е. для разных View, ViewObject будут разные, хоть и будут абстрагировать одну модель.
У вас получится, что слой Repository будет иметь методы getViewObject1() и getViewObject2().
В примере автора, о конкретном ViewObject будет знать только соответствующая конкретная реализация Presenter, что на мой взгляд несколько правильнее.
Спасибо за замечания!
1) Интерфейс Presenter в данный момент получился лишним, с этим я полностью согласен.
2) Абстрактный BasePresenter содержит в себе функцию управления подпиской, реализовывать это в каждом презентере = дублировать код.
3) Model слой и DTO. Тут палка о двух концах, с одной стороны независимость приложения от DTO, DBO и прочих моделей (которая в данный момент достигается за счет мапперов), с другой стороны жесткая связка Model (DataRepository) и прикладного приложения.
В данный момент в слое Model нет ни одного импорта из Presenter или View, мы можем перенести весь слой в другое приложение, он полностью независим. Также, как было сказано выше, при изменении model нужно переписать мапперы, View Object (а вместе с ними и остальной код) при этом не изменятся.
Расскажите как надо, с удовольствием посмотрим и обсудим!
НЛО прилетело и опубликовало эту надпись здесь
Честно не понял, о чём вы?) А если поменять формат передачи данных в примере на XML, то к чему ваш комментарий будет относиться?
Надо всем внимательно посмотреть на такой проект Google как JSONNET.

Маленький нюанс: Jsonnet — это не проект гугла. Вот вам цитата:

Jsonnet is not an official Google product (experimental or otherwise), it is just code that happens to be owned by Google.
НЛО прилетело и опубликовало эту надпись здесь
Хорошо, я спрошу иначе, как формат передачи данных относится к архитектуре и взаимодействию между компонентами внутри приложения?
НЛО прилетело и опубликовало эту надпись здесь
Опишите идею в контексте, в данном случае, MVP и Android.
НЛО прилетело и опубликовало эту надпись здесь
Для начала оффтоп — чтобы ответить на комментарий есть кнопка «Ответить», не нужно писать новый каждый раз.
Далее, вы куда-то уходите от идеи, C# тут появился уже:)… можете дать конкретный пример, ссылки?
Скажем есть база данных, простейшая. Есть экран со списком и с кнопкой, по нажатию идёт запрос в базу и заполняется список.
Какие ноды куда мне надо привязывать?
НЛО прилетело и опубликовало эту надпись здесь
Шизофрения какая-то в комментах пошла…
Ну я очень хотел понять, о чём говорил товарищ babylon :) Но комментом выше он решил слиться.
НЛО прилетело и опубликовало эту надпись здесь
Согласен, как ни старался, так и не понял причем тут JSON и архитектура.
НЛО прилетело и опубликовало эту надпись здесь
babylon похоже вы комментарии не в той статье пишите. Здесь разговор про Android+MVP, а вы говорите о JavaScript Object Notation, JSONNET и т. д.
НЛО прилетело и опубликовало эту надпись здесь
Товарищ, вы пишете, совершенно не разбираясь в теме. Каким образом то, что возвращает rest api поможет построить архитектуру android-приложения? Вы предлагаете в java вместо классов для модели хранить все в json? Не говоря об отвратительной скорости работы с этим (по сравнению с POJO), как вообще json может заменить нормальные, человеческие java-классы?
Дайте пример?) Или вы, сударь, трепло?)
НЛО прилетело и опубликовало эту надпись здесь
Классы те же объекты, только избыточные.

Wat??
Плохо приспоcбленные для разборки и сборки. Поэтому выдуваются всяческие костыли в виде DI.

Как связаны dependency injection и сборка/расборка объектов? Что такое вообще сборка объектов?
Причём тут REST API????

При том, что в статье идет речь о запросах к api, которые возвращают json.
Ощущение, что вы понятия не имеете о разработке на java и под android. Или просто троллите всех.
И да, используйте кнопку «Ответить».
НЛО прилетело и опубликовало эту надпись здесь
JSONPath этот ваще для школоты, а от XPath аж тошнит.
Стоит упомянуть, что пьяным заходить на хабр не стоит. Причем здесь дисплей-листы? Это вообще поприще компьютерной графики.

Скрытый текст
А на гитхабе у jsonpath читаем:
If you configure JsonPath to use the JacksonMappingProvider you can even map your JsonPath output directly into POJO's.

Как он мог такое предложить, объекты — это же фу-фу-фу, слой модели должен состоять из json-ов!
НЛО прилетело и опубликовало эту надпись здесь
Экась вы ловко со слоя model на view перескочили. Точно тролль.
То есть, вы gui на чистом opengl реализовываете? Понятно, почему вы такой нарезанный. Вас остается только пожалеть.
Но все же вернитесь к нашим баранам json-ам, если вам есть, что сказать по существу. И загляните под спойлер предыдущего сообщения. Или это вы так ловко обходите неприятные вам углы?
НЛО прилетело и опубликовало эту надпись здесь
Вот мне чисто для себя — вы разницу между Java и JavaScript улавливаете? Или canvas андроидовый? Ну, тогда вообще все очень плохо.
НЛО прилетело и опубликовало эту надпись здесь
Вы не нервничайте — и не будете промахиваться по кнопке «Ответить» :) Это ведь не удобно, вот вам пример)
По делу, официальную документацию к чему надо читать? Открыл документацию по Андроиду — вашу тему не нашёл.
НЛО прилетело и опубликовало эту надпись здесь
А ты, судя по всему, академик
Честно говоря, я давно так не смеялся читая комментарии :)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий