Moxy — библиотека, упрощающая реализацию паттерна MVP (Model View Presenter) в Android. Основные особенности использования:

Подробнее туттут и тут.

Пример использования:

1. Интерфейс View

interface MovieDescriptionView : MvpView {

    fun bindMovie(movie: UiFullMovie)

    @StateStrategyType(OneExecutionStateStrategy::class)
    fun openVideoActivity(videoUrl: String)
}

После того, как презентером был вызван bindMovie(), этот метод помещается в очередь вызовов viewstate c дефолтной стратегией (про стратегии по ссылкам выше много информации). При каждом возвращении View в активное состояние (после переворота экрана, возвращение на экран по стеку и т.д.) метод с параметрами будет вызван повторно, что позволяет держать экран в актуальном состоянии без ручной обработки восстановления экрана. Метод openVideoActivity() в силу примененной стратегии OneExecutionStateStrategy так себя не ведет, а вызывается один раз.

2. Presenter

@InjectViewState
class MovieDescriptionPresenter(private val movie: UiFullMovie) : MvpPresenter<MovieDescriptionView>() {

    override fun createComponent(component: ProjectComponent) {
        DaggerMocvieDescriptionComponent.builder()
                .projectComponent(component)
                .build()
                .inject(this)
    }

    override fun onFirstViewAttach() {
        super.onFirstViewAttach()
        viewState.bindMovie(movie)
    }

    fun onPlayTrailerClick(videoUrl: String) {
        viewState.openVideoActivity(videoUrl)
    }
}

Пример реализации Presenter'а, который работает с MovieDescriptionView. Метод onPlayTrailerClick() вызывается из фрагмента.

Важно: общение между View и Presenter происходит только в «одностороннем порядке». Например, правильная обработка SwipeRefreshLayout:код во фрагменте:

moviesRefreshLayout.setOnRefreshListener { presenter.reloadData() }

Код в презентере:

fun reloadData() {
    viewstate.startLoad()
    loadItems {
        viewstate.stopLoad()
        viewstate.swapData(it)
    }
}

View не должно подписываться на загрузку данных через презентер. View не должно забирать данные у презентера через get'еры. View только отображает данные и реагирует на пользовательские действия вызовом методов презентера.