MVI DSL

March 2, 2022 · View on GitHub

Начало работы

Для того, чтобы начать работать с DSL, необходимо унаследовать Middleware, использующийся в проекте, от [DslFlowMiddleware], и переопределить метод transform(eventStream) следующим образом:

    override fun transform(eventStream: Flow<SimpleEvent>): Flow<SimpleEvent> {
        return eventStream.transformations {
            // Здесь будут перечислены возможные трансформации
        }
    }

Добавление трансформаций

Для того, чтобы добавить эти трансформации, нужно вызвать либо метод addAll(vararg transformations: Flow<E>), либо унарный плюс: +Flow<T> для добавления по очереди.

Фильтрация по классу

Трансформации можно применять только к событиям определенных классов со следующим синтаксисом: <Класс события> <тип трансформации> <трансформация> Например, с помощью записи ниже, мы обновляем данные, как только получаем событие Reload: Reload::class eventToStream { loadData() }

Типы трансформаций

Названия некоторых транформаций в новой версии отличаются. Решено было изменить названия, чтобы они были сходу понятны при чтении и вызывали меньше путаницы при использовании.

mapTo -> eventToEvent
eventMapTo -> eventToStream
streamMapTo -> streamToStream
  1. eventToEvent - трансформация события в событие. Используется, когда например событие клика по кнопке нужно трансформировать в событие открытие диалога.
    В старой версии: mapTo
    ButtonClicked::class eventToEvent { OpenSelectPhotoDialog() } 
  1. eventToStream - трансформация события в поток событий. Полезно, например когда клик кнопки трансформируется в поток событий начала запроса к серверу, а когда ответ получен - в еще одно событие ошибки или успеха запроса. То есть получаем событие, а возвращаем поток событий.
    В старой версии: eventMapTo
    ReloadBtnClicked::class eventToStream { 
        interactor.loadData()
            .asRequest(LoadDataEvent())
    }
  1. streamToStream - трансформация потока событий в другой поток событий. Эта трансформация полезна, когда трансформации eventToEvent уже недостаточно и требуется модифицировать флоу событий, используя операторы реактивных цепочек. Например, filter, debounce, distinctUntilChanged и тд.
    В старой версии: streamMapTo
    TextChanged::class streamToStream { textChangedFlow -> 
        textChangedFlow
            .map { it.text } 
            .filter { it.isNotEmpty() }
            .debounce(300L, TimeUnit.MILLISECONDS)
            .distinctUntilChanged()
            .map { TextChangedDebounced(it) } 
    }
  1. react - когда нужно как-то отреагировать на событие, но не возвращать при этом никакого события в хаб. Например вызывать метод аналитики. То есть обратиться к чему-то, что при этом не потребует дальнейших обновлений состояния или трансформаций в другие события.
    ButtonClicked::class react { event -> 
        analyticsService.sendEvent(TEXT_CHANGED, event.text) 
    } 
  1. decompose (не поддерживается в текущей версии) - эта трансформация используется для обработки событий в другом Middleware. Например, на последних проектах в отдельный Middleware была вынесена логика обработки команд навигации, и на всех экранах, где требовалось совершать какие-то переходы в middleware, события навигации передавались для обработки в отдельный NavigationMiddleware.