17. Moxy – пример
:Задача сделать экран авторизации
• :По нажатию на кнопку входа
– Показать прогресс запроса
– Начать асинхронный запрос авторизации
• :После завершения асинхронного запроса авторизации
– Скрыть прогресса запроса
– ,Если авторизация прошла успешно то перейти на главный
экран
– ,Если пришла ошибка то показать диалог с ошибкой
18. Moxy – пример
:Задача сделать экран авторизации
:Решение
•Сделать SignInView
•Сделать SignInActivity
•Сделать SignInPresenter
19. Moxy – пример
@StateStrategyType(AddToEndSingleStrategy.class)
public interface SignInView extends MvpView {
void showProgress();
void hideProgress();
void showError(Throwable exception);
void hideError();
@StateStrategyType(SingleStateStrategy.class)
void onSignIn();
}
public class SignInActivity extends MvpActivity implements SignInView, UsersCounterView {
@InjectPresenter
SignInPresenter mSignInPresenter;
@InjectPresenter
UsersCounterPresenter mUsersCounterPresenter;
...
20. Moxy – пример
@InjectViewState
public class SignInPresenter extends MvpPresenter<SignInView> {
@Inject
Repository mRepository;
public SignInPresenter() {
SampleApplication.getAppComponent().inject(this);
}
public void auth(String login, String password) {
getViewState().hideError();
getViewState().showProgress();
mRepository.authentication()
.signIn(login, password)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
↓↓↓
↓↓↓
.subscribe(
ignored -> {
getViewState().hideProgress();
getViewState().onSignIn();
},
throwable -> {
getViewState().hideProgress();
getViewState().showError(throwable);
});
21. MoxyЖизненный цикл компонентов
View == Activity
PresenterStore: ,пока жив процесс получить доступ можно
через MvpFacade.getInstance().getPresenterStore()
Presenter:
LOCAL(default): пока View не финиширует
GLOBAL: пока живёт процесс
WEAK: пока не финишируют все View
ViewState: пока жив Presenter(в save state не сохраняется)
22. Советы
Presenter Presenter.init()Для инициализации сделайте метод
,Автокомплит работает сразу без компиляции проекта
Проект соберется даже без кодогенерации
Можно не использовать аннотации
MvpDelegate Viewпоможет превратить любой класс во
23. Как наладить диалоги
View:Между разными фантомный диалог
View1 Presenter1 Model Presenter2 View2→ → → →
Presenter:Между разными
Presenter1 Model Presenter2→ →
Как не :стоит делать
Presenter1 View Presenter2→ →
Editor's Notes
Всем привет,
Меня зовут Юра и я хочу рассказать вам о Moxy, о том как она устроена и как этим пользоваться
Вообще Moxy – это библиотека, реализующая MVP под Android. Поэтому для начала напомню, что такое MVP.
MVP – это шаблон проектирования пользовательского интерфейса. Почему именно пользовательского интрефейса, а не всего приложения?...
View – отвечает за пользовательский интерфейс приложения. Она отвечает только за передачу команд ... Хочется заметить, что в качестве устройства ввода/вывода может выступать не только дисплей …
И наконец Presenter. Presenter это по сути логика пользовательского интерфейса, логика View. Это связующее звено, которое знает как отреагировать на событие, произошедшие во View…
Довольно легко написать код, основанный на MVP. Для этого достаточно...
Но мы пришли к MVP по другой причине. Нам хотелось уйти от неудобных лоадеров. Лоадеры ... И в MVP мы нашли решение своей проблемы. Ведь если Presenter...
Отсюда появились такие требования к компонентам MVP:
1. Presenter должен спокойно переживать пересоздание View
2. В то же время, пересозданная View должна подключаться к уже работающему презентеру, а не создавать новый
3. А значит View при подключении к презентеру должна принять такой вид, который он от неё ожидает на данный момент. Например, если Presenter ожидает, что приаттаченная View показывает прогресс, то, как только View приаттачится к презентеру, она должна тут же показать прогресс.
Ну и конечно нам хотелось избежать boilerplate-кода. И вообще, чтобы все эти требования выполнялись сами собой. А нам не пришлось об этом беспокоиться.
Исходя из этих требований, мы решили сделать библиотеку Moxy.
Для начала рассмотрим схематично её компоненты, и как они взаимодействуют.
С моделью, вью и презентером вы уже знакомы. Ещё у Moxy есть ViewState. Можно подумать, что он хранит в себе флажки, которые говорят о том, как должна выглядеть View. Но это не так, потому что это не удобно. Поэтому ViewState помнит команды, которые Presenter передавал для View. И в тот момент, когда к презентеру цепляется новая View, ViewState отправляет к ней сохранённые команды, чтобы выполнив их, она стала выглядеть так, как этого ожидает Presenter. Хочется отметить, что у команд есть одна особенность: они умеют менять очередь команд вью стэйта. Например, команда может удалить себя из очереди команд после того, как будет первый раз применена ко View. Или полностью очистить очередь команд.
Теперь давайте рассмотрим схематичный пример, как работает Moxy.
Предположим, пользователь делает что-то со вью. Это событие передаётся в Presenter.
Presenter получив это событие, генерирует какую-то команду для View(предположим, «показать прогресс»).
Но эта команда уходит не напрямую во View, а сперва попадает во ViewState.
ViewState сохраняет её в очередь команд
И после этого передаёт её во View, которая применяет эту команду к себе
После этого наш Presenter делает какой-то асинхронный запрос в модель
И в результате этого запроса, презентер отправляет сперва одну команду во View(например, «скрыть прогресс»)
Которая так же уходит в очередь команд вью стэйта
И меняет очередь команд, удаляя оттуда команду «показать прогресс»
После чего команда «скрыть прогресс» применяется ко View
Затем Presenter отправляет очередную команду во вью(например, «покажи данные»), которая добавляется в очередь команд вью стэйта и применяется ко View.
И вдруг происходит вот что: пользователь поворачивает устройство
И View теряет своё правильное состояние.
Но тут ViewState замечает, что к презентеру приаттачилась новая вьюшка. Поэтому он применяет к ней последовательно хранившуюся очередь команды. И таким образом View принимает то самое состояние, которое у неё было до пересоздания.
Теперь давайте разберём пример, который покажет, как эта схема выглядит на деле.
Предположим, у нас есть экран авторизации, и нам нужно, чтобы у него было следующее поведение:
При нажатии на кнопку авторизации, нужно показать пользователю прогресс и начать асинхронный запрос авторизации
После завершения запроса, нужно скрыть прогресс и если авторизация прошла успешно, то провести пользователя внутрь приложения. Иначе, нужно показать пользователю ошибку.
Для того, чтобы нам реализовать такое поведение, придётся сделать три вещи:
Во-первых, написать интерфейс SignInView. Он будет просто описывать поведение View, чем позволит Moxy сгенерировать класс вью стэйта и его команды.
Затем нам нужна Activity, которая будет выступать в качестве View.
И наконец нам нужен Presenter, который будет реализовывать логику экрана
Вот непосредственно код, который придётся создать.
…….
Затем у нас определена Activity. Она наследуется от MvpActivity. Это позволяет не беспокоиться о том:
когда создавать Presenter или какой …
когда приаттачиться и детачиться от него
и в какой момент нужно сказать презентеру, что View финиширует и он может уничтожаться.
Дальше у нас определены поля с презентерами…
Так вот, оба эти презентера помечены аннотацией InjectPresenter. За счёт этого Moxy сама подставит в них нужные экземпляры презентеров, и мы сможем с ними взаимодействовать после вызова метода MvpActivity onCraete().
Приводить реализацию этой Activity я не буду, потому что во всех методах просто переключается visibility разных android-вью. Отмечу только то, что по клику на кнопку авторизации, в Presenter уходит соответствующая команда с данными из полей ввода логина и пароля.
Теперь мы приступаем к самому интересному компоненту - к презентеру.
… @InjectViewState, .. сгенерирует …, создаст экземпляр … сложит его в Presenter. Благодаря чему, метод презентера getViewState() всегда
…Repository, авторизуй пользователя асинхронно
И затем, ViewState, если …
Во-первых: логика экрана авторизации не привязана к тому, что и как отображается на дисплее. Может даже вовсе не быть ...
А также, за счёт того, что Presenter не привязан к .., вы можете смело использовать любой способ реализации ..
Ещё можно увидеть плюсы в удобстве тестирования такого презентера. Вы можете даггером подставлять нужный шедулер в Rx. И в момент теста инжектить синхронный шедулер. Тогда асинхронность превратится в синхронность, и не будет никаких проблем её протестировать.
В принципе текущих знаний вам должно хватить, чтобы начать успешно использовать Moxy.
Теперь я расскажу дополнительную информацию о Moxy, которая наверняка вам пригодится.
Сперва расскажу о продолжительности жизни основных компонентов Moxy.
Так же есть такая сущность как PresenterStore. Именно в ней хранятся все презентеры. Этот компонент живёт тоже до тех пор, пока не будет остановлен процесс, в котором он существует.
Интересней выглядит период жизни презентеров. В Moxy есть презентеры трёх типов, и у каждого из них свои правила существования.
локальные презентеры. чаще всего. Локальный Presenter живёт пока не финиширует View, для которой он создавался. Но он не будет уничтожен, если View будет пересоздаваться. Причём, этот механизм реализован довольно просто. ..
Напомню, что во вью стэйте живут не какие-нибудь флажки, говорящие о том, как должна выглядеть View, а список команд, применив которые, …. Поэтому довольно логично, что ViewState не может жить больше, чем живёт Presenter. Иначе что он будет собой отображать? Так же он не может жить меньше соответствующего презентера, т.к. в таком случае вновь приаттаченная вью не сможет получить список команд, чтобы принять актуальное состояние презентера.
А вот некоторые советы и замечания по поводу работы Moxy:
Если вам нужно для начала работы презентера какие-то входные параметры, то сделаете метод инициализации презентра.
[пример про детали новости]
Не смотря на большую роль кодогенерации, все автокомплиты будут работать из коробки. У вас не будет такого, что зафейленная кодогенерация будет мешать вам использовать автокомплит.
Мало того, проект даже будет собираться без кодогенерации. Правда, он будет падать в рантайме, но это другое дело =)
Ещё, можно совсем не пользоваться аннотациями, и кодогенерацией. Moxy позволяет вам всё делать самостоятельно: определять презентеры, писать код вью стэйта, самостоятельно создавать экземпляр вью стейте и складывать его в презентер. Или даже вовсе не использовать вью стэйт. Поэтому если вы захотите отказаться от мокси, мы сможете просто убрать аннотации и выключить кодогенерацию. Тогда у вас получится чистый MVP, и вам останется только связать между собой его компоненты….
Так же есть delegate..
На самом деле View не должна знать, что есть другая View. И тем более не должна хотеть что-то ей сообщить.. View может только передать действие пользователя в Presenter.