Fork me on GitHub

Как это работает?

Код разделён на пакеты client, shared, server и lib: первые три пакета содержат только код, относящийся к примеру, а последний пакет — код самой библиотеки.

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

В mvp4g-HistoryConverter модуля новое событие приходит в виде строки события и строки параметров (поэтому все навигационные события в приложении должны проходить через историю, это достигается через настройку шин событий). По двум этим строкам, воспользовавшись списком зарегистрированных страниц, описывающим связь страниц с событиями и лэйаутами, мы можем получить соответственно страницу, текущий URL и идентификатор лэйаута. Это происходит в методе convertFromToken класса PortalsHistoryConverter.

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

LayoutBuilder передаёт в абстрактный метод layout для дочернего класса текуший портал, состояние страницы (null, если его нет) и идентификатор лэйаута. По ним дочерний класс может однозначно определить, какими виджетами и в каком состоянии нужно заполнить плэйсходеры лэйаута через событие plug шины событий любого дочернего модуля. Событие plug передаётся в главный презентер и тот подключает “вилки” в “розетки” текущего лэйаута.

После этого класс PortalsHistoryConverter вызывает абстрактный метод covertFromUrl и передаёт в него полученный URL и идентификатор портала. По этому идентификатору портала дочерний конвертер может вызвать надлежащее навигационное событие.

Таким образом, сначала строится лэйаут страницы, а затем — вызывется навигационное событие. После выполнения навигационного пользователь может запрашивать изменение состояния через событие updateState(Place, State) для обновления состояния всей страницы (когда place == null) или её части. Это событие также обрабатывается главным презентером, который при необходимости либо обновляет лэйаут через LayoutBuilder, либо просто подменяет нужную “розетку”.

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

P.S. На данный момент в коде не используются ни аннотации, ни Dependency Injection, хотя возможно, надо бы.

[Содержание]