mvp что это android
Android MVP пример для начинающих. Без библиотек и интерфейсов.
В этом посте описывается несложный пример MVP, без использования запутывающих интерфейсов и сложных библиотек.
Что такое MVP
Сначала немного теории о MVP. Схематично это выглядит так:
Если в Activity пользователь нажал кнопку Обновить, то Activity сообщает об этом презентеру. При этом Activity не просит презентер загрузить данные. Оно просто сообщает, что пользователь нажал кнопку Обновить. А презентер уже сам решает, что по нажатию этой кнопки надо делать. Он запрашивает данные у модели и передает их в Activity, чтобы отобразить на экране.
Важное замечание! Пример реализации, который мы сейчас будем рассматривать, не является единственно правильным вариантом, выполненным по канонам MVP. В разных случаях могут быть шаги влево и вправо. Но общую концепцию этот пример отражает.
Практика
Я создал небольшое приложение и залил на гитхаб.
Приложение умеет добавлять, хранить и отображать список пользователей.
Чтобы наглядно показать отличие MVP, я сделал этот экран в двух вариантах: Activity и MVP. Вы можете выбрать нужный вариант при запуске:
Оба этих режима внешне будут выглядеть и работать одинаково, но «под капотом» они разные.
Такой вариант реализации считается тяжелым и неудобным. Слишком много всего возложено на один класс.
Давайте немного пройдемся по ключевым моментам кода. Сначала рекомендую вам посмотреть код SingleActivity, чтобы понять основные механизмы работы приложения. А я дальше буду описывать, как это было разделено по разным классам.
UsersModel
Это Model (модель). В модели обычно реализована работа с данными, например: запрос данных с сервера, сохранение в БД, чтение файлов и т.п.
Методам на вход можно передавать колбэки, которые будут вызваны по окончанию операции. Асинхронность работы с БД реализована с помощью AsyncTask. В методы добавления и удаления добавлены секундные паузы для наглядности.
UserActivity
Это View (представление). Представление отвечает за отображение данных на экране и за обработку действий пользователя.
В представлении не должно быть никакой логики. Это только инструмент для отображения данных и взаимодействия с пользователем.
Действия пользователя передаются в презентер. Обратите внимание на обработчики для кнопок Add и Clear. По нажатию на них, представление сразу сообщает об этом презентеру. И презентер уже будет решать, что делать.
Повторюсь, т.к. очень важно понимать это правильно. По нажатию на кнопки, Activity не просит презентер добавить пользователя или удалить всех пользователей. Т.е. оно не указывает презентеру, что ему делать. Оно просто сообщает, что была нажата кнопка Add или Clear. А презентер принимает это к сведению и действует по своему усмотрению.
UsersPresenter
Это Presenter (презентер). Он является связующим звеном между представлением и моделью, которые не должны общаться напрямую.
От представления презентер получает данные о том, какие кнопки были нажаты пользователем, и решает, как отреагировать на эти нажатия. Если надо что-то отобразить, то презентер сообщает об этом представлению. А если нужно сохранить/получить данные, он использует модель.
Давайте по шагам рассмотрим взаимодействие представления, презентера и модели на нашем примере. Возьмем сценарий добавления новых данных в базу.
1) Пользователь вводит данные в поля ввода. Это никак не обрабатывается и ничего не происходит.
2) Пользователь жмет кнопку Add. Вот тут начинается движ.
3) Представление сообщает презентеру о том, что была нажата кнопка Add.
4) Презентер просит представление дать ему данные, которые были введены пользователем в поля ввода.
5) Презентер проверяет эти данные на корректность.
6) Если они некорректны, то презентер просит представление показать сообщение об этом.
7) Если данные корректны, то презентер просит представление показать прогресс-диалог и просит модель добавить данные в базу данных.
8) Модель асинхронно выполняет вставку данных и сообщает презентеру, что вставка завершена
9) Презентер просит представление убрать прогресс-диалог.
10) Презентер просит свежие данные у модели.
11) Модель возвращает данные презентеру.
12 Презентер просит представление показать новые данные.
Из этой схемы видно, что презентер рулит всем происходящим. Он раздает всем указания, решает, что делать и как реагировать на действия пользователя.
Метод viewIsReady вызывается представлением, чтобы сообщить о том, что представление готово к работе. Презентер запрашивает у модели данные и просит представление отобразить их.
Плюсы MVP
Все плюсы вытекают из того, что вместо одного класса, мы используем несколько.
Что дальше?
Я создал этот пример, чтобы максимально просто показать реализацию MVP. Реальный рабочий пример будет содержать несколько важных дополнений. Кратко расскажу о них, чтобы вы представляли себе, куда двигаться дальше.
Интерфейсы.
Это то, что очень запутывает новичков в примерах MVP, но действительно является очень полезным инструментом.
Мы можем создать интерфейс UsersContractView
Добавить этот интерфейс в UsersActivity
Теперь в презентере можно убрать все упоминания о UsersActivity, и оставить только UsersContractView.
Плюс такого похода в том, что теперь в этом презентере вы можете использовать любое представление, которое реализует интерфейс UsersContractView. И вам не придется ничего менять в презентере.
А если презентер завязан на конкретный класс, например, UsersActivity, то при замене представления, вам придется открыть презентер и поменять там UsersActivity на другой класс.
Асинхронные операции
Создание объектов
В UsersActivity мы создаем презентер следующим образом:
Поворот экрана
В этом примере нет обработки поворота экрана. Если ваш презентер выполняет какую-то долгую операцию, и вы повернете экран, у вас просто создастся новый презентер, а результаты работы старого презентера могут быть потеряны.
Если тема MVP стала вам интересна, то посмотрите этот пример. Он посложнее и более приближен к реальному коду.
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Android. Пару слов об MVP + rxJava
Работая с Android часто можно видеть, как весь функциональный код помещается в методы жизненного цикла activity/fragment. В общем-то такой подход имеет некоторое обоснование — «методы жизненного цикла» всего лишь хэндлеры, обрабатывающие этапы создания компонента системой и специально предназначенные для наполнения их кодом. Добавив сюда то, что каркас UI описывается через xml файлы, мы уже получаем базовое разделение логики и интерфейса. Однако из-за не совсем «изящной» структуры жизненного цикла, его зависимости от множества флагов запуска, и различной (хоть и похожей) структуры для разных компонентов, эффективно воспользоваться подобным разделением не всегда бывает возможно, что в итоге выливается в написании всего кода в onCreate().
Model-View-Presenter+rxJava
MVP паттерн разработки для android, предлагающий разбивать приложение на следующие части:
Пример
Рассмотрим пример приложения, состоящего из одного экрана, на котором находится EditText и TextView. При этом по мере редактирования текста в EditText отправляются сетевые запросы, результат которых должен отображаться в TextView (конкретика запроса не должна нас волновать, это может быть перевод, краткая справка по термину или что то подобное).
Реализация
Так как Model и View используют одни и тебе виджеты (в нашем случае EditText и TextView) для своей работы, разумно будет реализовать содержащий их класс.
При реализации Model мы предполагаем использование rxAndroid, для «оборачивания» EditTetx, и retrofit для реализации сетевых запросов.
Так как количество сетевых запросов зависит от скорости набора текста (а она может быть достаточно высока), существует естественное желание ограничить частоту событий редактирование текста в EditText. В данном случае это реализуется оператором debounce (при этом, естественно, ввод текста не блокируется, а лишь пропускается часть событий редактирования, произошедших в временной промежуток в 150 миллисекунд).
Реализация activity, передающая всю сущностную часть работы Presenter:
Заключение
Хотя наш пример невероятно упрощен, в нем уже есть нетривиальные моменты связанные с контролем частоты событий. Представить же эволюцию нашего приложения в разрезе mvp довольно легко:
Ликбез про MVP в мобилках
В этой статье анализируется потребность в MVP, чтобы помочь бизнесу разрабатывать мобильные приложения, объясняя использование и ключевые преимущества.
Все начинается с идеи. Очень много именно на VC людей рассказывают о своих идеях и воплощениях. И это круто! После этого наступают действия. Для достижения лучших результатов выполнение должно быть таким, чтобы снизить риски, а также необходимо подумать как увеличивать производительность.
В последние годы разработка мобильных приложений развивается и движется вперед. Важным фактором является качество разрабатываемых продуктов. В результате, чтобы обеспечить лидерство на рынке, компаниям необходимо сосредоточиться на различных аспектах бизнеса.
MVP — это минимально жизнеспособный продукт. Это процесс разработки приложения, в котором основное внимание уделяется разработке базовой итерации мобильного приложения. Он фокусируется на основных преимуществах продукта, который помогает ориентироваться на пользователей.
MVP — это версия нового продукта. Это позволяет команде разработчиков мобильных приложений собирать максимальное количество подтвержденных сведений от клиентов. Этот процесс требует минимум усилий.
Приложение MPV содержит минимум функций и дизайна, которые являются важной и базовой частью разработки мобильных приложений. Это помогает определить реакцию пользователя на будущее приложение. Кроме того, это помогает изучить их взаимодействие.
Проще говоря, это способ проверить приложение перед запуском конечного продукта, который помогает фиксировать отзывы пользователей. Отзывы помогают улучшить продукт. Это избавляет от массовых отказов и помогает повысить рентабельность.
Когда мы хотим разработать мобильное приложение, у нас всегда есть два варианта. Для разработки мобильных приложений мы либо придерживаемся традиционного пути, то есть изначально вкладываемся в полноценную разработку приложения, либо можем использовать другой метод, например, MVP (минимально жизнеспособный продукт).
MVP помогает определить боли пользователя. А также определяет надлежащую функциональность для удовлетворения этих потребностей с течением времени. MVP помогает максимально быстро выпустить продукт на рынок и проверить насколько продукт будет удобен пользователю.
Этот процесс позволяет компаниям, которые планируют разработку приложения узнать, как пользователи реагируют на функции приложения. И с этим пониманием компании могут принимать логические решения о том, как достичь как бизнес-целей, так и продуктовых целей.
Создание и обслуживание мобильных приложений обходятся недешево. Поэтому компаниям, которые хотят заказать разработку мобильного приложения, стоит подумать об этом в первую очередь. Кстати мы как-то писали статью о том, сколько будет стоить создание мобильного приложения на подобии Telegram, ссылка тут
Итак, прежде чем приступить к созданию мобильного приложения, следует подумать о запуске минимально жизнеспособного продукта (MVP).
MVP помогает определить безопасный и недорогой способ тестирования концепции на рынке. Мобильное приложение может быть рискованным вложением для любого бизнеса, если к нему не подходить правильно. Кроме того, иногда наиболее хорошо изученные концепции приложений могут разочаровать пользователей. Это также приводит к более низким показателям удержания.
MVP помогает защитить ваши инвестиции и позволяет быстрее реализовывать проекты. Многие супер-успешные приложения сегодня начали свой путь с MVP, например, Facebook, Airbnb, Instagram, Dropbox, Uber и многие другие.
MVP обычно состоит из трех этапов обучения, сборки и измерения. Пока первые сторонники устанавливают и используют приложение, компании-разработчики мобильных приложений собирают и измеряют аналитические данные. Кроме того, они проводят интервью с клиентами, получают их отзывы и т. д. Все это помогает при тестировании приложений.
Результаты всегда меняются в зависимости от реакции конечных пользователей на приложение. Приложение может не оправдать ожиданий. Однако может случиться так, что конечным пользователям эти функции не понравятся или они не найдут для них полезного.
Конечно, благодаря MVP мы всегда можем вернуться и повторить все заново. Поскольку это разработка MVP гораздо дешевле по сравнению с традиционным методом, после прохождения теста мы можем продолжить добавление новых функций или улучшение существующих. Этот цикл продолжается и продолжается до жизненного цикла мобильного приложения.
В сегодняшнем процессе разработки мобильных приложений большинство компаний используют MVP. Его процесс помогает без сомнения показать, что клиенты будут или нет будут использовать продукт. Его функциональность строится с течением времени на основе данных пользовательского тестирования и отзывов.
Разработка приложения — важный шаг для небольших компаний, так как на рынке много конкурентов.
Минимально жизнеспособный продукт (MVP) определит рыночную стоимость идеи. Он определяет, как потребители отреагируют на конечный продукт. Кроме того, важно проанализировать, готовы ли тратить свои деньги.
После того, как у вас появится идея и путь, по которому вы будете следовать, вы можете начать добавлять функции в MVP. Это продолжается до тех пор, пока не достигнет своей финальной стадии. и ваших ожиданий.
MVP для Android — преимущества использования Moxy в качестве вспомогательной библиотеки
В данной статье описываются преимущества использования Moxy в качестве вспомогательной библиотеки при использовании MVP для Android-приложения.
Важно: здесь не сравнивается MVP с другими архитектурными подходами типа MVVM, MVI и т.п. В статье описывается почему, если в качестве архитектуры UI-ной части приложения выбран MVP, то лучше не использовать самописную реализацию MVP, а использовать Moxy.
Библиотека Moxy позволяет избежать boilerplate кода для обработки lifecycle фрагментов и активитей, и работать с View как будто оно всегда активно.
Далее под View понимается имплементация View в виде фрагмента или активити.
Под интерактором понимается сущность бизнес-логики, т.е. класс, который лежит на более низком уровне абстракции, чем Presenter.
Общие преимущества Moxy
Типичные задачи и решения
Рассмотрим, как решаются типичные задачи при разработке UI с использованием Moxy и без.
При решениях без Moxy предполагается следующая типичная реализация MVP. В presenter хранится nullable-ссылка на view. Presenter аттачится (передаётся ссылка на View) при создании View (в onCreate()) и детачится (зануляется ссылка на View) при уничтожении View (в onDestroy()).
Задача: асинхронный запрос данных и отображение результата на UI
Пусть у нас есть класс (MyListInteractor), который возвращает список данных. В presenter мы можем позвать его асинхронно для запроса данных.
Решение с Moxy
Обращаемся к не-nullable viewState и передаём туда загруженные данные. Моху прикопает результат и отправит View, когда оно будет активно. При пересоздании View команда может быть повторена (зависит от стратегии) при этом заново данные не будут запрашиваться.
Решение без Moxy
Обращаемся к View по nullable-ссылке. Эта ссылка зануляется при пересоздании View. Если к моменту завершения запроса view не приаттачена, то данные потеряются.
Возможное решение проблемы.
Прикапывать данные в какой-то сущности, которая не связана с View (например, в интеракторе). При onResume() запрашивать прихранённые данные и отображать их.
Минусы решения.
Задача: сохранение состояния отображения
Часто возникает ситуация, когда нам нужно хранить какое-то состояние отображения.
Решение с Moxy
Храним состояние в presenter. Presenter выживает при пересоздании View, поэтому там можно хранить состояние. Можно хранить данные любых типов, в т.ч. ссылки на интерфейсы, например.
Решения без Moxy
Можно хранить состояние в savedInstanceState или аргументах фрагмента.
Минусы решения
Можно хранить данные на уровне бизнес-логики, в специальном классе (пусть этот класс будет отвечать только за state конкретной View и не будет использоваться где-то ещё).
Минусы решения
Задача: обмен данными между экранами
Часто бывает нужно результат действий на одном View отобразить на другом View.
Решение с Moxy
Обмен данными между экранами осуществляется так же как и асинхронный запрос. Разве что подписка на изменения идёт на subject или channel в интеракторе, в который presenter другой View кидает изменённые данные. Подписка в Presenter.onFirstViewAttach(), отписка — в Presenter.onDestroy().
Решения без Moxy
Задача: инициализация чего-либо, связанного с экраном
Часто бывает нужно проинициализировать что-то, связанное с данным экраном. Например, какой-то внешний компонент.
Решение с Moxy
Проинициализировать компонент можно в Presenter.onFirstViewAttach() и освободить в Presenter.onDestroy() — это единственные коллбэки, о которых нам нужно задумываться.
Presenter.onFirstViewAttach() — вызывается при самом первом создании View,
Presenter.onDestroy() — вызывается при окончательном уничтожении View.
Решение без Moxy
Можно проинициализировать в onCreate() и освободить в onDestroy() активити или фрагмента.
Минусы решения
Задача: показ AlertDialog
Особенностью использования AlertDialog является то, что он пропадает при пересоздании View. Поэтому при пересоздании View нужно заново отображать AlertDialog.
Решение с Moxy
Выбрать правильную стратегию. Диалог сам перепокажется при пересоздании View.
Решения без Moxy
Особенности использования Moxy
Moxy позволяет избежать boilerplate кода при использовании MVP в android-приложении. Но, как и любой другой библиотекой, Moxy нужно научиться пользоваться. К счастью, использовать Moxy легко. Далее описаны моменты, на которые нужно обратить внимание.
Либо можно использовать кастомную стратегию с тегами. Например, как описано тут: https://habr.com/ru/company/redmadrobot/blog/341108/
Это нужно чтобы команда показа прогресса не вызвалась больше после команды скрытия прогресса.
Так делать нельзя. Нужно чтобы функция @ProvidePresenter гарантированно создавала новый инстанс presenter. Здесь при пересоздании фрагмента появится новый инстанс presenter. А Moxy будет работать со старым, т.к. функция providePresenter() вызывается только один раз.
Как вариант, можно в providePresenter() просто создать новый инстанс presenter:
Это не очень удобно — ведь придётся инжектить в фрагмент все зависимости этого presenter.
Можно из компонента dagger сделать метод для получения presenter и позвать его в providePresenter():
Важно, чтобы провайдер presenter’а и сам presenter не были помечены аннотацией Singleton.
В последних версиях Moxy можно использовать делегаты kotlin:
Ещё можно заинжектить через Provider:
Moxy — замечательная библиотека, которая позволяет значительно упростить жизнь android-разработчика при использовании MVP.
Как и с любой новой технологией или библиотекой, в начале использования Moxy неизбежно возникают ошибки, например, не верный выбор стратегии или не правильный inject Presenter’а. Однако с опытом всё становится просто и понятно и уже сложно себе представить MVP без использования Moxy.
Выражаю благодарность сообществу Moxy за такой замечательный инструмент. А так же участникам telegram-чата Moxy за ревью и помощь в написании статьи.
Ссылки
Moxy — реализация MVP под Android с щепоткой магии – отличная статья от разработчиков Moxy с описанием того, для чего создавалась Moxy и как с ней работать.
Стратегии в Moxy (часть 1) — статья хорошо описывает стандартные стратегии Moxy.
Стратегии в Moxy (Часть 2) — руководство по созданию кастомных стратегий Moxy.
Об использовании популярных практик в разработке под Android – высокоуровнево описывается MVP и Moxy.
Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile) – запись с конференции AppsConf, где разработчик Moxy рассказывает о том, как пользоваться библиотекой.
MVP и Dagger 2 – скелет Android-приложения – часть 1
Данная статья нацелена на новичков в Android-разработке и призвана помочь в создании минимально необходимой структуры приложения.
Так получилось, что я относительно недавно начал программировать под Android – после месяца без проекта в компании, где я работаю, меня определили в команду мобильной разработки в уругвайском офисе Tata Consultancy Services. При беседе с тимлидом команды мне был озвучен стек, с которым мне предстояло сначала ознакомиться, а затем и овладеть. В числе прочего был фреймворк Dagger 2 для DI и MVP в качестве архитектурного паттерна. И Kotlin. Но о нем в другой раз 🙂
Таким образом, я приступил к изучению сначала основы Android SDK, а затем и всего сопутствующего стека. С самим SDK проблем не возникло – исчерпывающей информации по нему в сети более чем достаточно, начиная с официальной документации и заканчивая туториалами (особенно с этим помог проект startandroid), но с Dagger 2 и MVP применительно к Android-разработке возникли некоторые затруднения ввиду довольно куцей документации первого и, на тот момент, недостаточного понимания второго. Дело в том, что до мобильной разработки я делал микросервисы на Java с использованием Spring Boot/MVC и уже имел достаточное представление и о том, что такое Dependency Injection, и о том, что такое MVC. При том, даже само название “Spring MVC” предполагает, что этот паттерн заложен в архитектуру проекта и его использование очевидно. От Dagger 2 я ожидал как такой же как в Spring “магии” и настолько же проработанной документации и туториалов. И обломался 😛
Тем не менее, при достаточном упорстве и усидчивости, нет ничего невозможного, а результатом изысканий стало осуществление моей давней идеи, возникшей еще в те времена, когда об Android-разработке я и не помышлял. Оценить идею вы можете, установив приложение из Google Store
В данной статье я хотел бы представить сухую выжимку результата моих поисков – пошаговое руководство по созданию скелета Android-приложения с использованием MVP и Dagger 2. Итак, начнем.
1.1 Abstracts
Для начала, создадим пакет abstracts в корне проекта, пусть это будет com.caesar84mx.mymvcapp.abstracts. В нем создадим 2 интерфейса: view.BaseView и presenter.BaseMvpPresenter. Следующим образом:
Это базовые архитектурные элементы, которые в дальнейшем будут использоваться в приложении. Далее, открываем BaseView и объявляем в него методы showView() getContext():
Теперь открываем BaseMvpPresenter и редактируем его следующим образом:
В пакете view создаем абстрактный класс BaseCompatActivity, наследуем его от AppCompatActivity и имплементируем недавно созданный интерфейс BaseView. Внутри класса объявляем абстрактный метод init(savedInstanceState: Bundle?) и имплементируем метод getContext() из BaseView:
От этого класса в дальнейшем мы будем наследовать все активности.
Теперь перейдем к презентеру – создадим класс BasePresenter, имплементирующий интерфейс BaseMvpPresenter и реализуем методы интерфейса следующим образом:
Отлично, базовые архитектурные элементы мы определили, теперь перейдем к компонентам, из которых будет строиться наше приложение.
1.2. Компоненты
Для начала, создадим пакет com.caesar84mx.mymvcapp.components, в нем пакет mainscreen, в котором, в свою очередь, пакеты ui и backstage, и перенесем в пакет ui класс MainScreen:
Теперь удалим из класса MainScreen автоматически сгенерированную при создании проекта имплементацию метода onCreate(), а также, наследование от AppCompatActivity и унаследуем его от BaseCompatActivity. Теперь реализуем метод init(), ранее объявленный в базовом классе. Весь код, который мы раньше поместили бы в метод onCreate(), мы поместим в него (как мы помним, метод init() вызывается в методе onCreate() базового класса):
Великолепно, элемент view паттерна MVP создан, теперь перейдем в закулисье нашего компонента – пакет backstage. Создадим интерфейс MainScreenContract – так называемый контракт, через который мы и будем реализовывать наш паттерн. В данном интерфейсе создадим 2 подинтерфейса — Presenter и View:
Теперь, перейдем к презетнеру и создадим класс MainScreenPresenter:
Скелет приложения почти готов, осталось несколько штрихов. В класс MainScreen добавим имплементацию интерфейса MainScreenContract.View, создадим и проинициализируем переменную presenter: MainScreenPresenter, а в методе init() присоединим вид к презентеру следующим образом:
Таким образом, мы создали презентер и добавили в него наш экземпляр view (не путать с android.view.View), который в презентере будет использоваться для манипуляций с видом.
1.3. Заключение первой части
Итак, мы создали базовые абстрактные элементы паттерна MVP, которые, однако, используются не напрямую, в лоб, а через т.н. контракт – базовый элемент каждого компонента приложения, который сочетает в себе как действия элемента view, так и действия элемента presenter. Контракт – достаточно гибкий элемент, состав которого варьирует от компонента к компоненту, ненавязчиво увязывая компоненты в рамках единой архитектуры.
Следует помнить, что в соответствии с концепцией MVP, элемент view должен быть максимально тупым, в нем мы производим только элементарные действия, такие, как, например, показать/спрятать текст, поменять фон или цвет текста, показать/спрятать значок загрузки и т.д. Методы, соответствующие этому элементу, мы определяем в подинтерфейсе View контракта. В то время, как логикой мы занимаемся в презентере – бизнес-логика, манипуляции данными (CRUD), запуск фоновых задач и т.д. В нем же мы решаем, когда и показать те или иные элементы на экране. В этом отличие от реализованной в спринге концепции MVC, где между бизнес-логикой и видом находится тупой контроллер, который только получает запросы от вида и вызывает сервис, который возвращает данные или выполняет иные действия, определенные бизнес-логикой. Методы, соответствующие презентеру, мы определяем в подинтерфейсе Presenter контракта.
При реализации презентера, манипуляции видом будут производиться через переменную view суперкласса BasePresenter, в то время, как методы, соответствующие view реализуются в классе активности.
Вы спросите, а где здесь Dagger 2 и зачем он нам сдался, не будет ли реализация DI в Android натягиванием совы на глобус? Ответ на второй вопрос – нет, не будет. А почему и зачем он нужен – во второй части моей статьи 😉