{"id":337778,"date":"2022-09-01T15:00:18","date_gmt":"2022-09-01T15:00:18","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=337778"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=337778","title":{"rendered":"<span>\u041e\u043f\u044b\u0442 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043d\u0430 MVI \u0432 Android \u043d\u0430 \u0431\u0430\u0437\u0435 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u044f<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c86\/3b5\/d62\/c863b5d629ac178b01abc470d1879b92.png\" width=\"780\" height=\"440\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c86\/3b5\/d62\/c863b5d629ac178b01abc470d1879b92.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041c\u044b \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c MVI \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u044d\u043a\u0440\u0430\u043d\u0430 \u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u0445\u043e\u0442\u0438\u043c \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u043f\u043e\u0447\u0435\u043c\u0443 \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c\u00a0 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f MVI-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u2014 Reduktor.<\/p>\n<h2>\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435<\/h2>\n<p>\u041d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d\u0438\u0439 \u0434\u0435\u043d\u044c \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 MVI \u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c\u044e, \u0435\u0433\u043e \u0432\u044b\u0431\u0438\u0440\u0430\u044e\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043f\u043e \u043c\u043d\u043e\u0433\u0438\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c. \u041e \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 MVI \u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0435\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u043c\u043d\u043e\u0433\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u0442\u0430\u0442\u044c\u0438<a href=\"http:\/\/hannesdorfmann.com\/android\/mosby3-mvi-1\"> <u>\u0425\u0430\u043d\u043d\u0435\u0441\u0430 \u0414\u043e\u0440\u0444\u043c\u0430\u043d\u0430 \u0432 \u0432\u043e\u0441\u044c\u043c\u0438 \u0447\u0430\u0441\u0442\u044f\u0445<\/u><\/a>. \u0422\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"https:\/\/www.youtube.com\/watch?v=hBkQkjWnAjg\"><u>\u0434\u043e\u043a\u043b\u0430\u0434 \u0421\u0435\u0440\u0433\u0435\u044f \u0420\u044f\u0431\u043e\u0432\u0430<\/u><\/a> \u00ab\u041a\u0430\u043a \u043f\u0440\u0438\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u0440\u043e\u0436\u0430\u0440\u0435\u043d\u043d\u044b\u0438\u0306 MVI \u043f\u043e\u0434 Android\u00bb<a href=\"https:\/\/www.youtube.com\/watch?v=hBkQkjWnAjg\"> <\/a>\u0438 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043e <a href=\"https:\/\/habr.com\/ru\/company\/badoo\/blog\/429728\/\"><u>\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 MVI-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0432 Badoo<\/u><\/a>.<\/p>\n<details class=\"spoiler\">\n<summary>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 MVI<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412\u043a\u0440\u0430\u0442\u0446\u0435, MVI (Model-View-Intent) \u2014 \u044d\u0442\u043e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0439 \u043f\u0430\u0442\u0442\u0435\u0440\u043d, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u0445\u043e\u0434\u0438\u0442 \u0432 \u0441\u0435\u043c\u0435\u0439\u0441\u0442\u0432\u043e \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432 Unidirectional Data Flow \u2014 \u043f\u043e\u0434\u0445\u043e\u0434 \u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0432\u0441\u0451 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0435 \u043e\u0434\u043d\u043e\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c. \u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 MVVM, MVI \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u0430\u043d\u043d\u044b\u0445 (Single source of true \u0438\u043b\u0438 SSOT). MVI \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0442\u0440\u0451\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432: \u0441\u043b\u043e\u044f \u043b\u043e\u0433\u0438\u043a\u0438, \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f (Model); UI-\u0441\u043b\u043e\u044f, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 (View); \u0438 \u043d\u0430\u043c\u0435\u0440\u0435\u043d\u0438\u044f (Intent).<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043a\u043b\u0438\u043a\u043d\u0435\u0442 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 \u00ab\u041e\u0442\u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c\u0441\u044f \u043d\u0430 \u0437\u0430\u044f\u0432\u043a\u0443\u00bb, \u0442\u043e \u043a\u043b\u0438\u043a \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 (Intent), \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435 \u0434\u043b\u044f Model. \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440, \u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u0431\u043d\u043e\u0432\u0438\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430. UI-\u0441\u043b\u043e\u0439 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u043d\u043e\u0432\u044b\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u0441\u043a\u0440\u043e\u0435\u0442 \u043a\u043d\u043e\u043f\u043a\u0443 \u0438 \u043f\u043e\u043a\u0430\u0436\u0435\u0442 \u0442\u0435\u043a\u0441\u0442 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0437\u0430\u044f\u0432\u043a\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0430.<\/p>\n<\/div>\n<\/details>\n<h2>\u041a\u0430\u043a \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0432 \u042e\u043b\u0435<\/h2>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u00ab\u041e\u0442\u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c\u0441\u044f \u043d\u0430 \u0437\u0430\u044f\u0432\u043a\u0443\u00bb, \u043a\u0430\u043a \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u0443 \u043d\u0430\u0441 \u0434\u043e \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f Reduktor. \u0417\u0430\u0440\u0430\u043d\u0435\u0435 \u0443\u0442\u043e\u0447\u043d\u044e, \u0447\u0442\u043e \u043c\u044b \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c RxJava.<\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441-\u043c\u0430\u0440\u043a\u0435\u0440 <code>UIEvent<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043a\u0430\u043a\u043e\u0435-\u043b\u0438\u0431\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435, \u0438 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u044b (\u043e\u0431\u044a\u0435\u043a\u0442\u044b) \u0441\u043e\u0431\u044b\u0442\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u044e\u0442\u0441\u044f \u043e\u0442 <code>UIEvent<\/code>. \u0421\u043b\u043e\u0439 Model \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 Android ViewModel, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0438\u0437\u0432\u043d\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f <code>UIEvent<\/code>. \u0412\u043d\u0443\u0442\u0440\u0438 ViewModel \u0435\u0441\u0442\u044c <code>viewStates: Flowable<\/code> \u2014 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430. \u041d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u043b\u043e\u0439 View.<\/p>\n<details class=\"spoiler\">\n<summary>Intent<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"kotlin\">interface UIEvent  object RespondClick : UIEvent()<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>State<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"kotlin\">data class ServiceDetailViewState(    val isLoading: Boolean,    val isRespondAvailable: Boolean )<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>Model<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"kotlin\">class ServiceDetailViewModel : ViewModel(), Consumer&lt;UIEvent> {     private val viewStateProcessor: BehaviorProcessor&lt;ServiceDetailViewState> = BehaviorProcessor.create()     \/\/ \u0422\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430 \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u044b\u0437\u043e\u0432\u0430    private val currentViewState: ServiceDetailViewState        get() = viewStateProcessor.value ?: ServiceDetailViewState(false, true)     private fun postViewState(vs: ServiceDetailViewState): Unit = viewStateProcessor.onNext(vs)     \/\/ \u041f\u043e\u0442\u043e\u043a \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u044d\u043a\u0440\u0430\u043d\u0430    val viewStates: Flowable&lt;ServiceDetailViewState> = viewStateProcessor.toSerialized()     \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0438\u0437\u0432\u043d\u0435    override fun accept(event: UIEvent) {        when (event) {            is RespondClick -> handleRespondClick()        }    }     \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043a\u043b\u0438\u043a\u0430 \u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430    private fun handleRespondClick() {        someNetworkCall()            .subscribeOn(Schedulers.io())            .observeOn(AndroidSchedulers.mainThread())            .doOnSubscribe { postViewState(currentViewState.copy(isLoading = true)) }            .subscribeBy(                onSuccess = { postViewState(ServiceDetailViewState(isRespondAvailable = false)) },                onError = { postViewState(currentViewState.copy(isLoading = false, isRespondAvailable = true)) }            )    } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>View<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"kotlin\">class ServiceDetailView {     \/\/ ..    \/\/ \u041f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f    viewModel.viewStates.subscribe { state ->        showLoading(state.isLoading)        showRespondButton(state.isRespondAvailable)    }     \/\/ \u041e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f RespondClick \u043f\u043e \u043a\u043b\u0438\u043a\u0443 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443    respondButton.setOnClickListener { viewModel.accept(RespondClick) } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u044b\u0448\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0430 \u0443\u043f\u0440\u043e\u0449\u0451\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u044b\u043b\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u042e\u043b\u044b.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f MVI \u0432 \u042e\u043b\u0435<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412 2018-\u043c \u0433\u043e\u0434\u0443 \u0432 Android \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043f\u043e\u043d\u044f\u0442\u0438\u044f MVVM \u0438 MVP \u0431\u044b\u043b\u0438 \u043d\u0430 \u0441\u043b\u0443\u0445\u0443. \u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 MVVM data-binding \u0431\u044b\u043b \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u043c \u043e\u0442 Google, \u043d\u043e \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0441 \u044d\u0442\u0438\u043c, \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c MVP \u043d\u0430\u0447\u0438\u043d\u0430\u043b\u0430 \u0441\u043f\u0430\u0434\u0430\u0442\u044c. \u041e\u0434\u043d\u0430\u043a\u043e, \u0441\u0435\u0440\u0435\u0431\u0440\u044f\u043d\u043e\u0439 \u043f\u0443\u043b\u0438 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u044b\u043b\u0438 \u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438, \u0438 \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u043a \u0447\u0430\u0441\u0442\u043e \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u044e\u0449\u0438\u043c\u0441\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f\u043c \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432.<\/p>\n<p>\u0427\u0442\u043e \u043d\u0435 \u0442\u0430\u043a \u0441 MVP?<\/p>\n<p>\u0412 MVP \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0443\u0434\u0430\u0432\u0430\u043b\u043e\u0441\u044c \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 Presenter, \u043d\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 View. \u042d\u0442\u043e \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u0435\u043c, \u0447\u0442\u043e \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043d\u0435\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432, \u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u044b \u0438\u043c\u0435\u043d\u043d\u043e \u043a \u044d\u043a\u0440\u0430\u043d\u0443 (\u0438\u043b\u0438 \u0435\u0433\u043e \u0447\u0430\u0441\u0442\u0438).<\/p>\n<p>\u0410 \u0447\u0442\u043e \u0441 MVVM?<\/p>\n<p>\u0412 MVVM \u043d\u0430 data-binding \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0440\u0430\u0437\u043d\u044b\u0435 \u043a\u0443\u0441\u043a\u0438 \u044d\u043a\u0440\u0430\u043d\u0430 \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u043b\u0438\u0441\u044c \u043a \u0440\u0430\u0437\u043d\u044b\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u043c \u0432\u043e ViewModel. \u041e \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438 \u043e\u0431\u044b\u0447\u043d\u043e \u043d\u0435 \u0437\u0430\u0434\u0443\u043c\u044b\u0432\u0430\u043b\u0438\u0441\u044c, \u0447\u0442\u043e \u043c\u043e\u0433\u043b\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u043a \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u043c c UX. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u0430\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0432 \u043a\u0430\u043a\u043e\u043c-\u043d\u0438\u0431\u0443\u0434\u044c \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u0431\u043b\u043e\u043a\u0435, \u0430 \u043d\u0438\u0436\u043d\u0438\u0439 \u0431\u043b\u043e\u043a \u0443\u0436\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0443\u044e \u043e\u0448\u0438\u0431\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043d\u0430\u0447\u0438\u043d\u0430\u043b \u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e.<\/p>\n<p>\u0418 \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u0432\u043e\u043f\u0440\u043e\u0441 &#8212; \u0447\u0442\u043e \u0436\u0435 \u0442\u0430\u043a\u043e\u0435 \u00abModel\u00bb \u0432 MVP\/MVVM? \u041e\u0431\u044b\u0447\u043d\u043e \u0432 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u043a\u043e\u0434\u0430\u00a0 \u043a\u043b\u0430\u0441\u0441 \u00abModel\u00bb \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u043b, \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u043b\u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438. \u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438? \u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0432\u043e ViewModel\/Presenter?<\/p>\n<p>\u0412 2018-\u043c \u043d\u0430\u043c \u043f\u043e\u043f\u0430\u043b\u0430\u0441\u044c \u0441\u0435\u0440\u0438\u044f \u0441\u0442\u0430\u0442\u0435\u0439 \u043e\u0442 Hannes Dorfman, \u0433\u0434\u0435 \u043e\u043d \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043b \u043f\u0440\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 MVI (ViewState, \u043c\u0435\u0442\u043e\u0434 render(), reducer, intent() \u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f) \u0438 \u0434\u0435\u043b\u0430\u043b \u043e\u0441\u043e\u0431\u044b\u0439 \u0430\u043a\u0446\u0435\u043d\u0442 \u043d\u0430 \u0442\u043e\u043c, \u0447\u0442\u043e \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u043e\u043b\u0436\u043d\u0430 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0445. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0442\u043e\u0439 \u0441\u0435\u0440\u0438\u0438 \u0441\u0442\u0430\u0442\u0435\u0439 \u043d\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043b\u0441\u044f (\u0430\u0432\u0442\u043e\u0440 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u043b \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438), \u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0431\u0449\u0435\u0439 \u043a\u0430\u0440\u0442\u0438\u043d\u0435 \u043c\u043e\u0436\u043d\u043e <a href=\"http:\/\/hannesdorfmann.com\/android\/model-view-intent\">\u0437\u0434\u0435\u0441\u044c<\/a>. \u0421\u0430\u043c\u043e\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u2014 Presenter \u0432 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u043a\u043e\u0434\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u043b, \u0431\u044b\u043b\u0430 ViewModel.<\/p>\n<p>\u0412 \u044d\u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f \u0432 Android-\u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u00ab\u042e\u043b\u044b\u00bb \u0441\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u043f\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u2014 \u0438\u0442\u043e\u0433\u043e \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u0441\u0442\u0430\u043b\u043e \u0430\u0436 \u0446\u0435\u043b\u044b\u0445 \u0442\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0432\u043c\u0435\u0441\u0442\u043e 2-\u0445. \ud83d\ude42 \u041f\u0440\u0438 \u0430\u043c\u0431\u0438\u0446\u0438\u043e\u0437\u043d\u043e\u043c \u043f\u043b\u0430\u043d\u0435 \u043f\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0443 \u0438 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0443 \u0444\u0438\u0447 \u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u043d\u0430 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433, \u0441\u0442\u0430\u043b\u043e \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0442\u044c \u043d\u0430\u043c \u043d\u0438\u0437\u043a\u0438\u0439 time to market, \u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c\u043e\u0435 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u043a\u043e\u0434\u0430 \u0438 \u043d\u0435\u0432\u044b\u0441\u043e\u043a\u0438\u0439 \u043f\u043e\u0440\u043e\u0433 \u0432\u0445\u043e\u0434\u0430. <\/p>\n<p>\u041e\u0442\u0441\u044e\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0432\u044b\u0434\u0435\u043b\u0438\u0442\u044c <strong>\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f<\/strong>:<\/p>\n<ol>\n<li>\n<p>\u041f\u0440\u0438\u043c\u0435\u043d\u0438\u043c\u043e\u0441\u0442\u044c \u0434\u043b\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432. TTM \u0441\u043e\u043a\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0437\u0430 \u0441\u0447\u0451\u0442 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443 \u043f\u0440\u043e\u0449\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f, \u0442\u0430\u043a \u043a\u0430\u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0444\u0438\u0447\u0438, \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u043f\u043e \u043e\u0434\u043d\u043e\u043c\u0443 \u0448\u0430\u0431\u043b\u043e\u043d\u0443;<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u0441\u0435\u0433\u043e \u043a\u043e\u0434\u0430, \u0447\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u043e\u0436\u043d\u043e (\u043c\u043e\u0434\u0435\u043b\u0438\/\u0441\u043e\u0431\u044b\u0442\u0438\u044f\/\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438\/use-case, \u0438 \u0434\u0440.);<\/p>\n<\/li>\n<li>\n<p>Unidirectional Data Flow \u2014 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043f\u043e \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u043e \u0432 \u043a\u0430\u0436\u0434\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0441\u043e\u043a\u0440\u0430\u0449\u0430\u0435\u043c \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u043e\u0442\u043b\u0430\u0434\u043a\u0443;<\/p>\n<\/li>\n<li>\n<p>Single Source of Truth \u2014 \u0435\u0441\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435* (\u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\u0445 \u043d\u0438\u0436\u0435), \u0430 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u2014 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u043d\u0430\u044f \u043e\u0442 \u043d\u0435\u0433\u043e. \u0418\u0441\u043a\u0430\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u044d\u0442\u043e\u0442 source of truth. UI \u043b\u043e\u0433\u0438\u043a\u0430 \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442, \u0430 \u043b\u0438\u0448\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442 \u043f\u0440\u0438\u0448\u0435\u0434\u0448\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u2014<code>render(state: ViewState)<\/code>;<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u043f\u0430\u0440\u0430\u0434\u0438\u0433\u043c\u044b: \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u044d\u043a\u0440\u0430\u043d\u044b \u0447\u0430\u0441\u0442\u043e \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0438\u0437-\u0437\u0430 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043b\u0435\u043d\u0442\u0430 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442 \u0444\u0438\u043b\u044c\u0442\u0440\u044b. \u041f\u043e\u0438\u0441\u043a \u2014 \u043f\u043e \u0432\u0432\u043e\u0434\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438\u043b\u0438 \u0441\u0430\u0434\u0436\u0435\u0441\u0442\u0430. \u042d\u043a\u0440\u0430\u043d \u0437\u0430\u043a\u0430\u0437\u0430 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u0437\u0430\u043a\u0430\u0437\u0430 \u0441 \u043f\u0443\u0448\u0430 \u0438\u043b\u0438 \u043f\u043e \u0432\u0435\u0431-\u0441\u043e\u043a\u0435\u0442\u0443. \u041c\u044b \u043e\u0436\u0438\u0434\u0430\u0435\u043c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f (\u0438\u043b\u0438 \u0441\u0435\u0440\u0438\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439) \u0438 \u0440\u0435\u0430\u0433\u0438\u0440\u0443\u0435\u043c \u043d\u0430 \u044d\u0442\u043e.<\/p>\n<\/li>\n<\/ol>\n<p>MVI \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u043b \u043f\u043e\u0434 \u044d\u0442\u043e \u043a\u0430\u043a \u043d\u0435\u043b\u044c\u0437\u044f \u043b\u0443\u0447\u0448\u0435. \u041e\u0434\u043d\u0430\u043a\u043e \u043c\u044b \u043f\u0435\u0440\u0435\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 Hannes\u2019\u0430 \u0438\u0437 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0441\u043e\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439. \u0410 \u0438\u043c\u0435\u043d\u043d\u043e:<\/p>\n<ol>\n<li>\n<p>\u041c\u044b \u043d\u0435 \u0441\u0442\u0430\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0432\u043e ViewModel \u0441\u043f\u0438\u0441\u043e\u043a <code>Observable&lt;UserIntent><\/code> \u0438 \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u043e\u0439. \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e ViewModel \u0441\u0442\u0430\u043b\u0430 <code>Consumer&lt;UIEvent><\/code>, \u0433\u0434\u0435 <code>UIEvent<\/code> \u2013 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 (\u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e <code>sealed class<\/code>), \u0432\u0441\u0435\u0433\u043e \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u043b\u043e \u0432\u043e View: \u044d\u0442\u043e \u0438 \u043a\u043b\u0438\u043a\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0438 \u0441\u0442\u0430\u0440\u0442 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f, \u0438 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430, \u0438 \u043e\u0442\u0432\u0435\u0442\u044b \u043e\u0442 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 sdk (\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u0432 <code>onActivityResult())<\/code>. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c,\u00a0 View \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u0441 ViewModel \u0447\u0435\u0440\u0435\u0437 \u043e\u0434\u0438\u043d \u043c\u0435\u0442\u043e\u0434 \u2014<code>consume()<\/code> (\u0438\u043b\u0438 <code>accept()<\/code>, \u0435\u0441\u043b\u0438 \u043c\u044b \u0431\u0435\u0440\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 RxJava);<\/p>\n<pre><code class=\"kotlin\">override fun accept(event: UIEvent) {    when (event) {        is FilterUiEvent.Init -> handleInit(event)        is BaseUiEvent.SaveState -> handleSaveState(event)        is BaseUiEvent.RestoreState ->handleRestoreState(event) ... }<\/code><\/pre>\n<\/li>\n<li>\n<p>View \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043e\u0434\u0438\u043d \u043c\u0435\u0442\u043e\u0434 \u2014<code>render(state: ViewState)<\/code>. View \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u044f, \u043a\u0430\u043a\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u0440\u0438\u0448\u043b\u043e, \u0442\u0430\u043a\u043e\u0435 \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f. ViewState \u043c\u044b \u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0438 \u0447\u0435\u0440\u0435\u0437 sealed-\u043a\u043b\u0430\u0441\u0441\u044b, \u0438 \u0434\u0435\u043b\u0430\u043b\u0438 \u0438\u0445 \u00ab\u043f\u043b\u043e\u0441\u043a\u0438\u043c\u0438\u00bb (\u0444\u043b\u0430\u0436\u043a\u0438 \u043e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435, \u043e\u0448\u0438\u0431\u043a\u0435, \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043b\u0435\u0436\u0430\u0442 \u0432 \u043e\u0434\u043d\u043e\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u0435), \u2014\u00a0 \u0432\u0441\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0440\u0430\u0431\u043e\u0447\u0438\u0435, \u043e\u0433\u0440\u043e\u043c\u043d\u044b\u0445 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432 \u0443 \u043a\u0430\u043a\u043e\u0433\u043e-\u0442\u043e \u043d\u0435\u0442;<\/p>\n<\/li>\n<li>\n<p>Reducer \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u0437\u0430\u043c\u0435\u043d\u044f\u043b\u043e \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435: <code>data class copy()<\/code>. \u041e\u0434\u043d\u0430\u043a\u043e \u0434\u043b\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0441 \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>reduce(state: ViewState, event: UIEvent)<\/code> \u043d\u0435 \u043b\u0435\u043d\u0438\u043b\u0438\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c;<\/p>\n<\/li>\n<li>\n<p>ViewModel \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0430 <code>states: Flowable&lt;ViewState><\/code>. \u0412\u043d\u0443\u0442\u0440\u0438 \u044d\u0442\u043e \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u0431\u044b\u043b\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u0447\u0435\u0440\u0435\u0437 <code>BehaviorProcessor&lt;ViewState>;<\/code><\/p>\n<\/li>\n<li>\n<p>\u0418\u0437 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0441\u043e\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439: ViewModel \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0430 <code>routeEvents: Flowable&lt;RouteEvent><\/code> \u0438 <code>serviceEvent: Flowable&lt;ServiceEvent>.<\/code>\u0421\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 <code>Router: Consumer&lt;RouteEvent><\/code> \u2014 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0435\u043c \u043f\u043e\u0442\u043e\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438, \u0438\u0437 \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0440\u043e\u0443\u0442\u0435\u0440\u043e\u0432 \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044f \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. ServiceEvent \u0441\u043b\u0443\u0436\u0438\u0442 \u0434\u043b\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u00abfire and forget\u00bb, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043d\u0435 \u0445\u043e\u0442\u0438\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u043e ViewState \u2013 \u043f\u043e\u043a\u0430\u0437\u044b \u0442\u0443\u043b\u0442\u0438\u043f\u043e\u0432, toast\u2019\u043e\u0432, \u0434\u0438\u0430\u043b\u043e\u0433\u0438-\u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438 \u0438 \u0442\u043e\u043c\u0443 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435;<\/p>\n<p><strong><em>\u0414\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440:<br \/>\u041c\u044b \u043d\u0435 \u043f\u0440\u0438\u0437\u044b\u0432\u0430\u0435\u043c \u0432\u0430\u0441 \u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a. \u0415\u0441\u043b\u0438 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u0445\u043e\u0434 (\u043d\u0430\u0432\u0438\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c) \u043f\u043e State \u0438\u043b\u0438 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u043e\u043a\u0430\u0437 toast, \u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 state, \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043b\u0438\u0448\u043d\u0438\u0445 \u043f\u043e\u0434\u043f\u0438\u0441\u043e\u043a. \u0412 \u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u043d\u0446\u043e\u0432, \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u043d\u0435 \u0430\u043a\u0430\u0434\u0435\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435, \u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0438 \u0434\u0435\u0448\u0451\u0432\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435<\/em><\/strong><\/p>\n<\/li>\n<li>\n<p>ViewModel \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u044f\u0432\u043b\u044f\u043b\u0430\u0441\u044c \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0435\u043d\u0438\u0435\u043c \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438, \u0438, \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0430\u0441\u044c \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0431\u044b\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0439 \u043d\u0430 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a Android;<\/p>\n<\/li>\n<li>\n<p>ViewModel \u043e\u0431\u0440\u0430\u0449\u0430\u043b\u0430\u0441\u044c \u043a repository, mapper\u2019\u0430\u043c, \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043b\u0430 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438, \u043c\u0435\u043d\u044f\u043b\u0430 \u0442\u0440\u0435\u0434\u044b, \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043b\u0430 \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438 \u043e\u0442\u0441\u044b\u043b\u0430\u043b\u0430 \u0435\u0433\u043e \u043d\u0430 UI;<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f,\u00a0 \u0434\u043b\u044f \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u0441\u0440\u0430\u0437\u0443 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u043b\u0438 DiffUtil, \u0434\u043e\u0431\u0438\u0432\u0430\u044f\u0441\u044c \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u043d\u0430 UI.<\/p>\n<\/li>\n<\/ol>\n<p><strong>\u0427\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0432 \u0438\u0442\u043e\u0433\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438:<\/strong><\/p>\n<ol>\n<li>\n<p>\u0421\u0442\u0430\u043b\u043e \u043f\u0440\u043e\u0449\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438. \u041d\u0435\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438 \u2014 \u0441\u043c. ViewModel. \u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u0448\u043b\u0438, \u043d\u043e \u043a\u0440\u0438\u0432\u043e\u0439 UI \u2014 \u0441\u043c. View. \u041a\u0440\u0438\u0432\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u2014 \u0441\u043c. \u043b\u043e\u0433\u0438 \u043f\u0440\u0438 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438\/\u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 state\u2019\u0430 \u0434\u043b\u044f View;<\/p>\n<\/li>\n<li>\n<p>\u042d\u0442\u043e \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u0438 \u043a \u043a\u043b\u0430\u0441\u0441\u0430\u043c \u0441 \u0440\u0430\u0437\u043d\u043e\u0439 \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c\u044e, \u0432\u0435\u0434\u044c \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0430\u043a\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u0434\u0430\u0442\u044c \u044d\u0442\u043e \u0440\u0430\u0437\u043d\u044b\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c \u0434\u043b\u044f \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0422\u0422\u041c;<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u043f\u043e \u0432\u0441\u0435\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e. \u041e\u0431\u0449\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0434\u043b\u044f \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439;<\/p>\n<\/li>\n<li>\n<p>\u041e\u0431\u0449\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0434\u043b\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u044e\u0449\u0438\u0445\u0441\u044f fire-and-forget \u0441\u043e\u0431\u044b\u0442\u0438\u0439.<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0440\u0435\u043b\u0438\u0437\u0430 \u043f\u0438\u043b\u043e\u0442\u043d\u043e\u0439 \u0444\u0438\u0447\u0438 \u043d\u0430 MVI \u043c\u044b \u0437\u0430\u0432\u0435\u043b\u0438 25 \u0431\u0430\u0433\u043e\u0432 \u0438 \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u043b\u0438 \u0438\u0445 \u0437\u0430 4 \u0447\u0430\u0441\u0430 \u2013 \u043d\u0430\u043c \u0441\u0442\u0430\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e \u043a\u0430\u043a, \u0433\u0434\u0435 \u0438 \u0447\u0442\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u043f\u0440\u0430\u0432\u0438\u0442\u044c. \u0418\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u0443\u0431\u0435\u0434\u0438\u043b\u043e \u043d\u0430\u0441 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0430\u0448\u0438\u043c \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f\u043c. \u041d\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u044f\u043b \u0435\u0449\u0451 \u0438 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b\u043b \u0441\u043e\u0432\u043c\u0435\u0449\u0435\u043d \u0441 \u043f\u0435\u0440\u0435\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 \u0434\u0438\u0437\u0430\u0439\u043d\u0430 \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e. \u0418 \u0434\u0430\u0436\u0435 \u0437\u0434\u0435\u0441\u044c \u043d\u0430\u043c \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0432\u0441\u0451 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c: \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u0438, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u0434\u0438\u0437\u0430\u0439\u043d \u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0443\u043f\u0430\u0441\u0442\u044c \u043f\u043e crash-free. Profit!<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u0440\u0435\u043c\u044f \u0448\u043b\u043e, \u0444\u0438\u0447\u0438 \u0443\u0441\u043b\u043e\u0436\u043d\u044f\u043b\u0438\u0441\u044c, \u0438 \u043c\u044b \u043e\u0431\u0440\u0430\u0442\u0438\u043b\u0438 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0447\u0438\u0441\u0442\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443. \u0421\u0442\u0430\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e ViewModel \u0431\u043e\u043b\u0435\u0435 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0447\u0435\u0442\u0430\u0442\u044c \u0441\u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438, \u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u043b\u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443 \u0432 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u043e\u0440\u044b. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c, \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u043e\u0440\u044b \u0431\u044b\u043b\u0438 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u043c\u0438 &#8212; \u0441\u043c. <a href=\"https:\/\/www.youtube.com\/watch?v=ENYE2AAhLjc\">\u0434\u043e\u043a\u043b\u0430\u0434 \u0410. \u0427\u0435\u0440\u0432\u044f\u043a\u043e\u0432\u0430 \u043e state-\u043c\u0430\u0448\u0438\u043d\u0430\u0445 \u043d\u0430 \u0441\u043b\u043e\u0435 domain<\/a>. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043f\u043e\u043d\u044f\u0442\u044c, \u0447\u0442\u043e \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c 2 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f: \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0444\u0438\u0447\u0438 \u0438 ViewState \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0430 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c, \u0443 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u0432\u043e\u0431\u043e\u0434\u0430 \u0432 \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0432\u044f\u0437\u0435\u0439 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u043e\u0440\u043e\u0432 \u0432\u043d\u0443\u0442\u0440\u0438 ViewModel.<\/p>\n<p>\u0424\u0440\u0435\u0434\u0435\u0440\u0438\u043a \u0411\u0440\u0443\u043a\u0441 \u0441\u0447\u0438\u0442\u0430\u043b, \u0447\u0442\u043e: \u201c&#8230;\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u0438\u0437\u0432\u043d\u0435 \u0443\u0441\u0438\u043b\u0438\u0432\u0430\u0435\u0442, \u0430 \u043d\u0435 \u043f\u043e\u0434\u0430\u0432\u043b\u044f\u0435\u0442 \u0442\u0432\u043e\u0440\u0447\u0435\u0441\u043a\u0443\u044e \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u0433\u0440\u0443\u043f\u043f\u044b \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u0435\u0439\u201d. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043d\u0430\u0448\u0443 \u0441\u0445\u0435\u043c\u0443 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u044e\u0449\u0438\u0439 \u043a\u0443\u0441\u043e\u0447\u0435\u043a: \u0430 \u0438\u043c\u0435\u043d\u043d\u043e, \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043e\u0431\u0449\u0438\u0439 \u0448\u0430\u0431\u043b\u043e\u043d \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043b\u044e\u0431\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 (use-case\u2019\u043e\u0432 \/ interactor\u2019\u043e\u0432), ViewModel \u0441 ViewState, \u0438 \u043d\u0430\u0448\u0438\u0445 \u043f\u043e\u0434\u043f\u0438\u0441\u043e\u043a \u0441 RouteEvent\/ServiceEvent. \u042d\u0442\u043e\u0442 \u043e\u0431\u0449\u0438\u0439 \u043a\u0443\u0441\u043e\u0447\u0435\u043a \u043c\u044b \u0445\u043e\u0442\u0435\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432 \u0432\u0438\u0434\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\/\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<h2>\u041f\u043e\u0438\u0441\u043a \u0433\u043e\u0442\u043e\u0432\u043e\u0433\u043e MVI-\u0440\u0435\u0448\u0435\u043d\u0438\u044f<\/h2>\n<p>\u041a\u043e\u043d\u0435\u0446 2020 \/ \u043d\u0430\u0447\u0430\u043b\u043e 2021-\u0433\u043e \u0433\u043e\u0434\u0430. \u041a\u043e\u043c\u0430\u043d\u0434\u0430 Android-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u044b\u0440\u043e\u0441\u043b\u0430 \u043f\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0443. \u041f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0433\u0438\u0431\u043a\u0438\u0439, \u043f\u0440\u043e\u0441\u0442\u043e\u0439, \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u043e \u043a\u043e\u0434\u0443 MVI-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043d\u0443\u0436\u043d\u044b\u0435 \u043d\u0430\u043c \u043a\u0435\u0439\u0441\u044b, \u0432\u043d\u0435\u0434\u0440\u0438\u0442\u044c \u0432 \u043a\u0440\u0430\u0442\u043a\u0438\u0435 \u0441\u0440\u043e\u043a\u0438; \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b \u043d\u0435 \u0438\u043c\u0435\u043b \u043e\u0449\u0443\u0442\u0438\u043c\u044b\u0439 \u043f\u043e\u0440\u043e\u0433 \u0432\u0445\u043e\u0434\u0430.<\/p>\n<p>\u041c\u044b \u043d\u0430\u0447\u0430\u043b\u0438 \u0438\u0441\u043a\u0430\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0435 open source \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0438\u0445 \u0432 \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442. \u0420\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c\u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f\u043c\u0438 \u043a \u043a\u043e\u0434\u0443, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u043c\u0443 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0433\u043e\u0442\u043e\u0432\u043e\u0433\u043e MVI-\u0440\u0435\u0448\u0435\u043d\u0438\u044f:<\/p>\n<ol>\n<li>\n<p><strong>\u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u044c \u0438 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043e\u0442 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0438 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a.<\/strong> \u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u043a\u0440\u0430\u0439\u043d\u0435 \u0433\u0438\u0431\u043a\u043e\u0439 \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c\u043e\u0439. \u041a\u0430\u043a \u0441\u043a\u0430\u0437\u0430\u043d\u043e \u0432\u044b\u0448\u0435, \u0441\u0435\u0439\u0447\u0430\u0441 \u0443 \u043d\u0430\u0441 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f RxJava, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043c\u044b \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u043c \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043d\u0430 compose \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c coroutines \u0432 \u043d\u0435\u0434\u0430\u043b\u0435\u043a\u043e\u043c \u0431\u0443\u0434\u0443\u0449\u0435\u043c. \u041e\u0442\u0441\u044e\u0434\u0430 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435: \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0437\u0430\u0432\u0438\u0441\u0435\u0442\u044c \u043e\u0442 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a;<\/p>\n<\/li>\n<li>\n<p><strong>\u0421\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u0435\u043c\u043e\u0441\u0442\u044c.<\/strong> \u0427\u0435\u043c \u043f\u0440\u043e\u0449\u0435 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438 \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0432 \u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0430\u0446\u0438\u044e, \u0442\u0435\u043c \u043b\u0435\u0433\u0447\u0435 \u043d\u043e\u0432\u044b\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442;<\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0430\u0434\u0435\u0436\u043d\u043e\u0441\u0442\u044c.<\/strong> \u0412\u043d\u0443\u0442\u0440\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0439 \u0441\u0440\u0435\u0434\u044b. \u0415\u0434\u0438\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0442\u044c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432;<\/p>\n<\/li>\n<li>\n<p><strong>\u0422\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u044c;<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f;<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u041b\u0435\u0433\u043a\u0430\u044f \u0432\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c\u043e\u0441\u0442\u044c \u0432 \u043f\u0440\u043e\u0435\u043a\u0442;<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u0414\u0435\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0438 \u0445\u043e\u0440\u043e\u0448\u043e \u0447\u0438\u0442\u0430\u0435\u043c\u044b\u0435 \u043b\u043e\u0433\u0438.<\/strong><\/p>\n<\/li>\n<\/ol>\n<p>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u0439 \u2014 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u043e, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u0435\u0451 \u0434\u043e\u043b\u0436\u043d\u044b \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0432 \u043f\u043e\u0440\u044f\u0434\u043a\u0435.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0438\u0449\u0435\u0442\u0435 \u0442\u0430\u043a\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u0442\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u0441\u0442\u0430\u0442\u044c\u044e \u00ab<a href=\"https:\/\/habr.com\/ru\/company\/simbirsoft\/blog\/661185\/\"><u>\u0421\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u043c \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 MVI-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u043d\u0430 Android<\/u><\/a>\u00bb, \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e \u043d\u0430 2022 \u0433\u043e\u0434. \u0412 \u043d\u0430\u0447\u0430\u043b\u0435 2021 \u0433\u043e\u0434\u0430, \u043c\u044b \u043e\u0442\u043c\u0435\u043b\u0438 MVICore \u043e\u0442 Badoo, \u043a\u0430\u043a \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0441\u043b\u043e\u0436\u043d\u044b\u0439. MVIKotlin \u043d\u0435 \u0438\u043c\u0435\u043b \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u0438, \u043a\u0430\u043a \u0441\u0435\u0439\u0447\u0430\u0441. \u0418\u0442\u043e\u0433\u043e, \u043c\u044b \u0437\u0430\u0432\u0435\u043b\u0438 \u0434\u0435\u043c\u043e-\u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 github, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043b\u0438 RxRedux \u0438 \u043f\u0435\u0440\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e Reduktor, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043d\u0430\u043c \u043f\u0440\u0438\u043d\u0451\u0441 \u043d\u0430 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0438\u0435 \u043d\u0430\u0448 \u043a\u043e\u043b\u043b\u0435\u0433\u0430. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 Reduktor \u043f\u043e\u043a\u0440\u044b\u0432\u0430\u043b \u0432\u0441\u0435 \u043d\u0430\u0448\u0438 \u043d\u0443\u0436\u0434\u044b, \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 RxRedux, \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0431\u044b\u043b \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u043d \u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043b\u043e\u0441\u044c \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442. \u0412 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d \u0432\u0435\u0440\u0441\u0438\u044f \u043d\u0430 RxJava \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 \u0433\u043e\u0434\u0430, \u043f\u043e\u043b\u0451\u0442 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u044b\u0439.<\/p>\n<h2>\u041f\u0440\u043e Reduktor<\/h2>\n<p>\u0412 Reduktor \u0432\u0441\u0451 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u043e\u0431\u044a\u0435\u043a\u0442 <code>Store<\/code>. \u041a\u043b\u0430\u0441\u0441 <code>Store<\/code> \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u043e\u0432\u0430\u043d \u0434\u0432\u0443\u043c\u044f \u0442\u0438\u043f\u0430\u043c\u0438: <code>ACTION<\/code> \u2014 \u0431\u0430\u0437\u043e\u0432\u044b\u043c \u043a\u043b\u0430\u0441\u0441\u043e\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0439, \u0438 <code>STATE<\/code> \u2014 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u044b.<\/p>\n<p>\u041a\u0430\u043a\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0435\u0441\u0442\u044c \u0443 <code>Store<\/code>:<\/p>\n<pre><code class=\"kotlin\">class Store&lt;ACTION, STATE>(    initialState: STATE,    private val reducer: Reducer&lt;ACTION, STATE>,    initializers: Iterable&lt;Initializer&lt;ACTION, STATE>> = emptyList(),    sideEffects: Iterable&lt;SideEffect&lt;ACTION, STATE>> = emptyList(),    private val logger: Logger = Logger {},    private val newStatesCallback: (state: STATE) -> Unit )<\/code><\/pre>\n<ul>\n<li>\n<p><code>initialState<\/code> \u2014 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430;<\/p>\n<\/li>\n<li>\n<p><code>reducer<\/code> \u2014 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043d\u043e\u0432\u043e\u0433\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0432 \u043d\u043e\u0432\u043e\u0435;<\/p>\n<\/li>\n<li>\n<p><code>initializers<\/code> \u2014 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0438\u0437 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432. \u0418\u0445 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043b\u044e\u0431\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e (\u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 0). \u0423 \u043a\u043b\u0430\u0441\u0441\u0430 <code>Initializer<\/code> \u0435\u0441\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f <code>ActionsInitializer<\/code> \u0441 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u043c \u043f\u043e\u043b\u0435\u043c <code>actions<\/code>, \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>post<\/code>;<\/p>\n<\/li>\n<li>\n<p><code>sideEffects<\/code> \u2014 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u044b\u0432\u0430\u044e\u0442 \u043d\u043e\u0432\u043e\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0432 \u043f\u043e\u0442\u043e\u043a \u043d\u043e\u0432\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439. \u0418\u0445 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043b\u044e\u0431\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e (\u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 0). \u041c\u043e\u0433\u0443\u0442 \u043d\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435, \u0435\u0441\u043b\u0438 \u043e\u043d\u043e \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f. \u0418\u043c\u0435\u043d\u043d\u043e \u0432 \u043d\u0438\u0445 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0432 \u0441\u0435\u0442\u044c;<\/p>\n<\/li>\n<li>\n<p><code>logger<\/code> \u2014 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0441\u0435\u0433\u043e, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435: \u043a\u0430\u043a\u043e\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043f\u0440\u0438\u0448\u043b\u043e, \u043a\u0430\u043a\u043e\u0435 \u0441\u0435\u0439\u0447\u0430\u0441 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438 \u043a\u0430\u043a\u043e\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 (\u0438\u043b\u0438 \u0447\u0442\u043e \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u043e\u0441\u044c). \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e <code>null<\/code>;<\/p>\n<\/li>\n<li>\n<p><code>newStatesCallback<\/code> \u2014 \u043a\u043e\u043b\u043b\u0431\u044d\u043a, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435. \u0412\u043d\u0443\u0442\u0440\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0435\u0441\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u043d\u0430 \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u044c. \u041a\u043e\u0433\u0434\u0430 \u0441\u043e\u0437\u0434\u0430\u043d \u043e\u0431\u044a\u0435\u043a\u0442 <code>Store<\/code>, \u0432 <code>newStatesCallback<\/code> \u0441\u0440\u0430\u0437\u0443 \u043f\u0440\u0438\u0434\u0451\u0442 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u043f\u043e\u0442\u043e\u043a\u0435. \u041e\u0434\u043d\u0430\u043a\u043e \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u044c \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u043f\u043e\u0442\u043e\u043a\u0430\u0445.<\/p>\n<\/li>\n<\/ul>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/df8\/a14\/ed3\/df8a14ed32249ac383a6476f7ebf8ece.png\" width=\"510\" height=\"286\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/df8\/a14\/ed3\/df8a14ed32249ac383a6476f7ebf8ece.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430, \u0443 \u043a\u043b\u0430\u0441\u0441\u0430 <code>Store<\/code> \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0439 \u0434\u043b\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 \u043f\u043e\u0442\u043e\u043a\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0447\u0435\u0440\u0435\u0437 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 <code>StateFlow<\/code> (Coroutines) \u0438 <code>Flowable<\/code> (RxJava2, RxJava3).<\/p>\n<p>\u041f\u0440\u0438\u043d\u0446\u0438\u043f \u0440\u0430\u0431\u043e\u0442\u044b:<\/p>\n<ul>\n<li>\n<p>\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043f\u0430\u0441\u0442\u044c \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0447\u0435\u0440\u0435\u0437 <code>Initializer<\/code>. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043e\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c \u0438\u043b\u0438 \u043b\u044e\u0431\u043e\u0435 \u0434\u0440\u0443\u0433\u043e\u0435 \u0432\u043d\u0435\u0448\u043d\u0435\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0438\u0437 \u0441\u043e\u043a\u0435\u0442\u0430).<\/p>\n<\/li>\n<li>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 <code>Reducer<\/code>. \u0422\u0443\u0442 \u043e\u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0432\u043b\u0438\u044f\u0442\u044c \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u0415\u0441\u043b\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u043e\u0441\u044c, \u0442\u043e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e\u0431 \u044d\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0430 \u0442\u0435\u043c, \u043a\u0442\u043e \u043d\u0430 \u043d\u0435\u0433\u043e \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043b\u0441\u044f.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0438 \u043d\u043e\u0432\u043e\u0435 (\u043b\u0438\u0431\u043e \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u0432\u0448\u0435\u0435\u0441\u044f) \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442 \u0432 <code>SideEffect<\/code>. \u041e\u0442\u0442\u0443\u0434\u0430 \u043c\u043e\u0433\u0443\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043d\u043e\u0432\u044b\u0435 \u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u0441 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u043c\u0438. \u041f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u0441\u044f \u043d\u0430 \u043d\u0438\u0445 \u0438 \u043e\u0436\u0438\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0441\u043d\u043e\u0432\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b \u0432 <code>Reducer<\/code>. \u0412 <code>SideEffect<\/code> \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0444\u043e\u043d\u043e\u0432\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438, \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u044b \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043d\u043e\u0432\u043e\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435.<\/p>\n<\/li>\n<\/ul>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9c5\/4a6\/6ce\/9c54a66ce8433660351632466e211819.png\" width=\"510\" height=\"286\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9c5\/4a6\/6ce\/9c54a66ce8433660351632466e211819.png\"\/><figcaption><\/figcaption><\/figure>\n<h2>Reduktor \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435<\/h2>\n<p>\u0412 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043f\u0440\u0438\u043d\u0446\u0438\u043f \u0440\u0430\u0431\u043e\u0442\u044b Reduktor \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u044d\u043a\u0440\u0430\u043d\u0430 \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. \u041e\u043d \u043c\u043e\u0436\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0442\u0440\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f: \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430, \u043e\u0448\u0438\u0431\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u0438\u0437 \u0441\u0435\u0442\u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. \u041f\u043e \u043a\u043b\u0438\u043a\u0443 \u043d\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0442\u044c\u0441\u044f webview. \u0414\u043b\u044f \u0440\u0430\u0441\u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0432\u0430\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c RxJava. \u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0442\u0430\u043a\u043e\u0433\u043e \u044d\u043a\u0440\u0430\u043d\u0430:<\/p>\n<pre><code class=\"kotlin\">data class FeatureViewState(    val isLoading: Boolean = false,    val error: Throwable? = null,    val data: List&lt;User> = listOf() )<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f, \u0432 \u043d\u0430\u0448\u0435\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u043e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0434\u0432\u0443\u0445 \u0442\u0438\u043f\u043e\u0432:<\/p>\n<ul>\n<li>\n<p>\u0432\u043d\u0435\u0448\u043d\u0438\u0435, \u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u2014 <code>FeatureViewAction<\/code>;<\/p>\n<\/li>\n<li>\n<p>\u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435, \u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u2014 <code>FeatureSideAction<\/code>.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u0441\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c \u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 <code>FeatureAction<\/code>, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0442\u043e\u043c \u0438\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 Reduktor:<\/p>\n<pre><code class=\"kotlin\">interface FeatureAction  sealed class FeatureViewAction : FeatureAction {    object Init : FeatureViewAction()    object Retry : FeatureViewAction()    class Click(val user: User) : FeatureViewAction() }  sealed class FeatureSideAction : FeatureAction {    class Data(val data: List&lt;String>) : FeatureSideAction()    class Error(val error: Throwable) : FeatureSideAction() }<\/code><\/pre>\n<p>\u0412 \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f <code>FeatureViewAction.Init<\/code> \u0438 <code>FeatureViewAction.Retry<\/code> \u0434\u043e\u043b\u0436\u043d\u0430 \u043d\u0430\u0447\u0430\u0442\u044c\u0441\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0432 \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 <code>FeatureViewAction.Click<\/code> \u0434\u043e\u043b\u0436\u043d\u0430 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0442\u044c\u0441\u044f webview. \u0412\u0441\u0451 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0432 \u043e\u0434\u043d\u043e\u043c side-\u044d\u0444\u0444\u0435\u043a\u0442\u0435. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 <code>SideEffect<\/code> \u0438 \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>invoke<\/code>:<\/p>\n<pre><code class=\"kotlin\">class FeatureLogicSideEffect : SideEffect&lt;FeatureAction, FeatureViewState> {     override fun Environment&lt;FeatureAction>.invoke(action: FeatureAction, state: FeatureViewState) {        \/\/ ..    } }<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434 <code>invoke<\/code> \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 (<code>action<\/code>) \u0438 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 (<code>state<\/code>).<\/p>\n<p>\u0421\u0443\u0449\u043d\u043e\u0441\u0442\u044c <code>Environment<\/code> \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0437\u0430\u0434\u0430\u0447\u0430\u043c (<code>tasks<\/code>) \u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u043c (<code>actions<\/code>). \u0427\u0442\u043e\u0431\u044b \u0432 Reduktor \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0444\u043e\u043d\u043e\u0432\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u043a\u043b\u0430\u0441\u0441\u0430 <code>Task<\/code> \u0438 \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0432 \u043c\u0430\u0441\u0441\u0438\u0432 <code>tasks<\/code>. \u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u0438 \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u043c\u043e\u0436\u043d\u043e \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0442\u043e\u0434 <code>release()<\/code>.<\/p>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0447\u0430\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u044d\u043a\u0440\u0430\u043d\u0430, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0437\u0430\u0434\u0430\u0447\u0443 <code>tasks[\u201dload_data\u201d]<\/code>:<\/p>\n<pre><code class=\"kotlin\">private fun Environment&lt;FeatureAction>.loadData() {    tasks[\"load_data\"] = repository.loadData()        .subscribeOn(Schedulers.io())        .toTask(            onSuccess = { actions.post(FeatureSideAction.Data(it)) },            onError = { actions.post(FeatureSideAction.Error(it)) }        ) }<\/code><\/pre>\n<p>\u041a\u043b\u044e\u0447 \u0437\u0430\u0434\u0430\u0447\u0438 \u0437\u0430\u0434\u0430\u0451\u0442\u0441\u044f \u0434\u043b\u044f \u0435\u0451 \u043e\u0442\u043c\u0435\u043d\u044b \u0441 \u0442\u0430\u043a\u0438\u043c \u0436\u0435 \u043a\u043b\u044e\u0447\u043e\u043c. \u041c\u0435\u0442\u043e\u0434 <code>toTask<\/code> \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442 \u0442\u0438\u043f Single (RxJava) \u0432 \u0442\u0438\u043f <code>Task<\/code> (\u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 Reduktor). \u0412 \u043e\u0431\u0440\u0430\u0442\u043d\u044b\u0445 \u0432\u044b\u0437\u043e\u0432\u0430\u0445 <code>onSuccess<\/code> \u0438 <code>onError<\/code> \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>actions.post<\/code>.<\/p>\n<p>\u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 <code>FeatureLogicSideEffect<\/code> \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"kotlin\">class FeatureLogicSideEffect(    private val repository: FeatureRepository,    private val router: FeatureRouter ) : SideEffect&lt;FeatureAction, FeatureViewState> {     override fun Environment&lt;FeatureAction>.invoke(action: FeatureAction, state: FeatureViewState) {        when (action) {            is FeatureViewAction.Init,            is FeatureViewAction.Retry -> loadData()            is FeatureViewAction.Click -> router.openBrowser(action.user.url)        }    }     private fun Environment&lt;FeatureAction>.loadData() {        tasks[\"load_data\"] = repository.loadData()            .subscribeOn(Schedulers.io())            .toTask(                onSuccess = { actions.post(FeatureSideAction.Data(it)) },                onError = { actions.post(FeatureSideAction.Error(it)) }            )    } }<\/code><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u043c side-\u044d\u0444\u0444\u0435\u043a\u0442\u0435 \u043c\u044b \u0442\u0430\u043a\u0436\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438, \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0441 \u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439 \u043f\u043e \u043a\u043b\u0438\u043a\u0443 \u043d\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 (\u0441\u043c. <code>FeatureViewAction.Click<\/code>).<\/p>\n<details class=\"spoiler\">\n<summary>\u041d\u044e\u0430\u043d\u0441\u0438\u043a\u0438<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043e\u0442\u0432\u043b\u0435\u0447\u0451\u043c\u0441\u044f \u043e\u0442 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0438 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u044e\u0430\u043d\u0441\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u0442\u044c\u0441\u044f \u0432 side-\u044d\u0444\u0444\u0435\u043a\u0442\u0430\u0445.<\/p>\n<ul>\n<li>\n<p><strong>\u0417\u0430\u0446\u0438\u043a\u043b\u0438\u0432\u0430\u043d\u0438\u0435<\/strong>. \u041d\u0435 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043b\u044f Reduktor \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430, \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u0446\u0438\u043a\u043b\u0438\u0442\u044c\u0441\u044f, \u0435\u0441\u043b\u0438 \u0432\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043b\u0438 \u0442\u0430\u043a\u043e\u0435 \u0436\u0435 \u043e\u0431\u0440\u0430\u0442\u043d\u043e:<\/p>\n<pre><code class=\"kotlin\">override fun Environment&lt;FeatureAction>.invoke(action: FeatureAction, state: FeatureViewState) {    when (action) {        is FeatureAction.Init -> {            doSomething()            actions post FeatureAction.Init \/\/ \u0417\u0430\u0446\u0438\u043a\u043b\u0438\u0432\u0430\u043d\u0438\u0435!        }    } }<\/code><\/pre>\n<\/li>\n<li>\n<p><strong>\u041d\u0435\u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435<\/strong>. \u041d\u0443\u0436\u043d\u043e \u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u044b\u0437\u043e\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u0430 <code>invoke<\/code>. \u0415\u0441\u043b\u0438 \u043f\u043e\u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u0437\u0430\u0431\u0440\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u043f\u043e\u043b\u044f <code>state<\/code> \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u043e\u043a\u0430, \u0442\u043e \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u043e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0443\u0436\u0435 \u0434\u0440\u0443\u0433\u0438\u043c\u0438. \u041d\u0443\u0436\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u0431\u043b\u043e\u043a\u0438 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438\u0437 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438:<\/p>\n<pre><code class=\"kotlin\">override fun Environment&lt;FeatureAction>.invoke(action: FeatureAction, state: FeatureViewState) {    when (action) {        is FeatureAction.Load -> {            tasks[\"load_and_save\"] = load(state.id)                .subscribeOn(ioScheduler)                .flatMap {                    \/\/ \u041e\u0431\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a state \u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u043e\u043a\u0430.                    \/\/ \u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u044b\u0437\u043e\u0432\u0430 id \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0443\u0436\u0435 \u0434\u0440\u0443\u0433\u0438\u043c.                    return@flatMap save(state.id, it)                        .subscribeOn(ioScheduler)                }                .toTask(onSuccess = { actions post FeatureAction.Complete() })        }    } }<\/code><\/pre>\n<pre><code class=\"kotlin\">\/\/ \u0418\u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044e  override fun Environment&lt;FeatureAction>.invoke(action: FeatureAction, state: FeatureViewState) {    when (action) {        is FeatureAction.Load -> {            tasks[\"load_data\"] = load(state.id)                .subscribeOn(ioScheduler)                .toTask(onSuccess = { actions post FeatureAction.Save(it) })        }        is FeatureAction.Save -> {            tasks[\"save_data\"] = save(state.id, action.param)                .subscribeOn(ioScheduler)                .toTask(onSuccess = { actions post FeatureAction.Complete() })        }    } }<\/code><\/pre>\n<\/li>\n<\/ul>\n<\/div>\n<\/details>\n<p>\u0420\u0430\u043d\u0435\u0435 \u043c\u044b \u043e\u043f\u0438\u0441\u0430\u043b\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430, \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0438 \u0438\u0445 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0432 <code>SideEffect<\/code>. \u0412 side-\u044d\u0444\u0444\u0435\u043a\u0442\u0435 \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0442\u043e\u0436\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f.<\/p>\n<p>\u0414\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0432 Reduktor \u0435\u0441\u0442\u044c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c <code>Reducer<\/code>. \u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c <code>Reducer<\/code> \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u044d\u043a\u0440\u0430\u043d\u0430. \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u043d\u043e\u0432\u044b\u0439\u00a0 <code>state<\/code> \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e:<\/p>\n<pre><code class=\"kotlin\">class FeatureReducer : Reducer&lt;FeatureAction, FeatureViewState> {     override fun FeatureViewState.invoke(action: FeatureAction): FeatureViewState {        val state = this        return when (action) {            is FeatureViewAction.Init,            is FeatureViewAction.Retry -> state.copy(isLoading = true, error = null)            is FeatureSideAction.Data -> state.copy(isLoading = false, error = null, data = action.data)            is FeatureSideAction.Error -> state.copy(isLoading = false, error = action.error)            else -> state        }    } }<\/code><\/pre>\n<p>\u0412\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0435 \u043c\u044b \u043e\u043f\u0438\u0441\u0430\u043b\u0438, \u0442\u0435\u043f\u0435\u0440\u044c \u0441\u0432\u044f\u0436\u0435\u043c \u0438\u0445 \u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u0435 <code>Store<\/code>:<\/p>\n<pre><code class=\"kotlin\">private val logicSideEffects = FeatureLogicSideEffect(repository, router) private val featureReducer = FeatureReducer() private val actionsInitializer = ActionsInitializer&lt;FeatureAction, FeatureViewState>()  val store: Store&lt;FeatureAction, FeatureViewState> = Store(    initialState = FeatureViewState(),    reducer = featureReducer,    initializers = listOf(actionsInitializer),    sideEffects = listOf(logicSideEffects),    logger = { Timber.d(\"FEATURE_TAG | $it\") } )  fun accept(action: FeatureViewAction) {    actionsInitializer.actions.post(action) }<\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u043b\u043e\u0441\u044c \u043f\u0440\u0438 \u0441\u043c\u0435\u043d\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438, \u043f\u043e\u043b\u043e\u0436\u0438\u043c \u043e\u0431\u044a\u0435\u043a\u0442 <code>Store<\/code> \u0432 Android ViewModel. \u0418, \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u043f\u043e\u0434\u043f\u0438\u0448\u0435\u043c\u0441\u044f \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u044d\u043a\u0440\u0430\u043d\u0430 \u0438 \u043e\u043f\u0438\u0448\u0435\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0432 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b:<\/p>\n<pre><code class=\"kotlin\">disposable = viewModel.store.states    .observeOn(AndroidSchedulers.mainThread())    .subscribe { state ->    \/\/ \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c UI } .... \/\/ \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f viewModel.accept(FeatureViewAction.Init) .... \/\/ \u043a\u043b\u0438\u043a \u043f\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0443 \u0441\u043f\u0438\u0441\u043a\u0430 val action = FeatureViewAction.Click(user) viewModel.accept(action) .... \/\/ \u043a\u043b\u0438\u043a \u043f\u043e \u043a\u043d\u043e\u043f\u043a\u0435 \u043f\u043e\u0432\u0442\u043e\u0440\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 viewModel.accept(FeatureViewAction.Retry) ....<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u044d\u043a\u0440\u0430\u043d \u0438 \u0438\u0437\u0443\u0447\u0430\u0435\u043c \u043b\u043e\u0433<\/summary>\n<div class=\"spoiler__content\">\n<p>FEATURE_TAG | &#8212;&#8212;&#8212;INIT&#8212;&#8212;&#8212;<br \/>FEATURE_TAG | STATE\u00a0 : FeatureViewState(isLoading=false, error=null, data=[])<br \/>FEATURE_TAG | THREAD : main<br \/>FEATURE_TAG | &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br \/>FEATURE_TAG | &#8212;&#8212;-ACTION&#8212;&#8212;-<br \/>FEATURE_TAG | ACTION > FeatureViewActionReload@f3f1eab<br \/>FEATURE_TAG | STATE\u00a0 > FeatureViewState(isLoading=false, error=null, data=[])<br \/>FEATURE_TAG | STATE\u00a0 &lt; FeatureViewState(isLoading=true, error=null, data=[])<br \/>FEATURE_TAG | THREAD : main<br \/>FEATURE_TAG | &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br \/>FEATURE_TAG | &#8212;&#8212;TASK-ADDED&#8212;&#8212;<br \/>FEATURE_TAG | ID \u00a0 \u00a0 : 1<br \/>FEATURE_TAG | KEY\u00a0 \u00a0 : load_data<br \/>FEATURE_TAG | THREAD : main<br \/>FEATURE_TAG | &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br \/>FEATURE_TAG | &#8212;&#8212;-ACTION&#8212;&#8212;-<br \/>FEATURE_TAG | ACTION > FeatureSideAction&#187; class=&#187;formula inline&#187;>Data@2dffdb4<br \/>FEATURE_TAG | STATE\u00a0 > FeatureViewState(isLoading=true, error=null, data=[])<br \/>FEATURE_TAG | STATE\u00a0 &lt; FeatureViewState(isLoading=false, error=null, data=[item 1, item 2])<br \/>FEATURE_TAG | THREAD : RxCachedThreadScheduler-1<br \/>FEATURE_TAG | &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br \/>FEATURE_TAG | &#8212;-TASK-REMOVED&#8212;-<br \/>FEATURE_TAG | ID \u00a0 \u00a0 : 1<br \/>FEATURE_TAG | KEY\u00a0 \u00a0 : load_data<br \/>FEATURE_TAG | THREAD : RxCachedThreadScheduler-1<br \/>FEATURE_TAG | &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<\/p>\n<\/div>\n<\/details>\n<p>\u0412 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u044f\u0432\u0438\u0442\u044c \u0444\u0430\u043d\u0442\u0430\u0437\u0438\u044e \u0438 \u0432\u0441\u0442\u0440\u043e\u0438\u0442\u044c Reduktor \u0432 \u043b\u044e\u0431\u043e\u0435 \u043c\u0435\u0441\u0442\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430, \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043c\u0435\u0434\u0438\u0430\u0444\u0430\u0439\u043b\u043e\u0432, \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0444\u0438\u0447\u0438, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0435\u0439 \u0438\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432, \u0438 \u0442.\u0434. \u041e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u043a \u0441\u0438\u0441\u0442\u0435\u043c\u0435 side-\u044d\u0444\u0444\u0435\u043a\u0442\u044b, \u0437\u0430\u0434\u0430\u0447\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e coroutines \u0438 RxJava, \u0447\u0442\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0434\u043b\u044f \u043f\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043e\u0434\u043d\u043e\u0433\u043e \u043a \u0434\u0440\u0443\u0433\u043e\u043c\u0443.<\/p>\n<h2>\u041d\u0430\u0448 \u043e\u043f\u044b\u0442<\/h2>\n<p>\u041d\u0430\u0448\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u0431\u044b\u043b\u043e \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0430\u0445 \u0440\u0430\u0431\u043e\u0442\u044b \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438. \u041c\u044b \u043d\u0435 \u0441\u0442\u0430\u043b\u0438 \u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0436\u0451\u0441\u0442\u043a\u043e\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u0441\u0435 \u044d\u043a\u0440\u0430\u043d\u044b \u043d\u0430 Reduktor, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0432 \u0441\u043e\u0432\u0441\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u043a\u043e\u0434, \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u0431\u0443\u0434\u0435\u0442 \u0438\u0437\u043b\u0438\u0448\u043d\u0435 \u043d\u0430\u0433\u0440\u0443\u0436\u0435\u043d \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044f\u043c\u0438. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c Reduktor, \u0435\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0442\u0434\u0435\u043b\u0438\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0444\u0438\u0447\u0438 \u043e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u044d\u043a\u0440\u0430\u043d\u0430. <\/p>\n<p>\u0412\u043e\u0437\u044c\u043c\u0451\u043c \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u044d\u043a\u0440\u0430\u043d \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430: \u043e\u043d \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043e\u0434\u043d\u043e\u0433\u043e RecyclerView \u0438 ViewPager \u0434\u043b\u044f \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0442\u043e\u0432\u0430\u0440\u0430 \u0432 \u0448\u0430\u043f\u043a\u0435. \u041a\u0430\u0436\u0434\u044b\u0439 \u0431\u043b\u043e\u043a \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u044d\u043a\u0440\u0430\u043d\u0430 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c\u044e. \u0412\u0441\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0433\u043e \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 \u0444\u0438\u0447\u0438 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0432\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f: \u043e\u0434\u043d\u043e \u0434\u043b\u044f \u044d\u043a\u0440\u0430\u043d\u0430 \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438, \u0434\u0440\u0443\u0433\u043e\u0435 \u2014 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0435 \u0441 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u044d\u043a\u0440\u0430\u043d\u0430, \u043d\u0435\u043d\u0443\u0436\u043d\u044b\u043c\u0438 \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438. \u041a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043c\u043e\u0434\u0435\u043b\u044c \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430, \u0430 \u043e\u043d\u043e, \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0443. \u0421 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u043c \u043d\u0430 Reduktor \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0430 \u044d\u0442\u043e\u0433\u043e \u044d\u043a\u0440\u0430\u043d\u0430 \u0431\u044b\u043b\u0430 \u0434\u0435\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u043d\u0430 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e side-\u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432, \u043e\u0442\u0447\u0435\u0433\u043e \u043a\u043e\u0434 \u0441\u0442\u0430\u043b \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0447\u0438\u0449\u0435 \u0438 \u043f\u0440\u043e\u0449\u0435 \u0432 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0435 \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0438. \u0415\u0441\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 side-\u044d\u0444\u0444\u0435\u043a\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0438 \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u044d\u043a\u0440\u0430\u043d\u0430\u0445.<\/p>\n<p>\u041e\u0442\u043b\u0430\u0434\u043a\u0430 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u0441\u0442\u0430\u043b\u0430 \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u043c\u0435\u043d\u044c\u0448\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0442\u0430\u043a \u043a\u0430\u043a \u043b\u044e\u0431\u043e\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0435\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 Reduktor \u043b\u043e\u0433\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 \u0443\u0434\u043e\u0431\u043e\u0447\u0438\u0442\u0430\u0435\u043c\u043e\u043c \u0432\u0438\u0434\u0435 (\u0441\u043c. \u043f\u0440\u0438\u043c\u0435\u0440 \u0432\u044b\u0448\u0435).<\/p>\n<p>\u0412 \u043d\u0435\u0434\u0430\u043b\u0435\u043a\u043e\u043c \u0431\u0443\u0434\u0443\u0449\u0435\u043c \u043f\u043b\u0430\u0432\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043d\u0430 compose \u0438 coroutines \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u0442\u0438\u0447\u043d\u044b\u043c \u0441 MVI-\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435. \u0427\u0442\u043e\u0431\u044b \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c \u043f\u043e\u0442\u043e\u043a \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0442\u0438\u043f\u0430 <code>Flowable<\/code> (RxJava) \u043d\u0430 <code>StateFlow<\/code> (coroutines), \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442 \u043a\u043b\u0430\u0441\u0441\u0430 <code>Store<\/code> \u043d\u0430 \u0442\u043e\u0442, \u0447\u0442\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043f\u0430\u043a\u0435\u0442\u0435 reduktor.coroutines. \u041d\u0430 \u043f\u043e\u0442\u043e\u043a \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 <code>StateFlow<\/code> \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 \u0432 composable view. \u0412 <code>SideEffect<\/code> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 c RxJava \u043d\u0430 coroutines. \u0427\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0442\u0438\u043f Reduktor <code>Task<\/code> \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f extention-\u043c\u0435\u0442\u043e\u0434\u043e\u043c \u043a <code>CoroutineScope<\/code>: <code>CoroutineScope.newTask<\/code>.<\/p>\n<p><strong>* * *<\/strong><\/p>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Reduktor, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e \u043f\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044e \u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u043d\u0430 <a href=\"https:\/\/github.com\/g000sha256\/reduktor\"><u>GitHub<\/u><\/a>.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/youla\/blog\/685888\/\"> https:\/\/habr.com\/ru\/company\/youla\/blog\/685888\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041c\u044b \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c MVI \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u044d\u043a\u0440\u0430\u043d\u0430 \u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u0445\u043e\u0442\u0438\u043c \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u043f\u043e\u0447\u0435\u043c\u0443 \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c\u00a0 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f MVI-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u2014 Reduktor.<\/p>\n<h2>\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435<\/h2>\n<p>\u041d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d\u0438\u0439 \u0434\u0435\u043d\u044c \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 MVI \u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c\u044e, \u0435\u0433\u043e \u0432\u044b\u0431\u0438\u0440\u0430\u044e\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043f\u043e \u043c\u043d\u043e\u0433\u0438\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c. \u041e \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 MVI \u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0435\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u043c\u043d\u043e\u0433\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u0442\u0430\u0442\u044c\u0438<a href=\"http:\/\/hannesdorfmann.com\/android\/mosby3-mvi-1\"> <u>\u0425\u0430\u043d\u043d\u0435\u0441\u0430 \u0414\u043e\u0440\u0444\u043c\u0430\u043d\u0430 \u0432 \u0432\u043e\u0441\u044c\u043c\u0438 \u0447\u0430\u0441\u0442\u044f\u0445<\/u><\/a>. \u0422\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"https:\/\/www.youtube.com\/watch?v=hBkQkjWnAjg\"><u>\u0434\u043e\u043a\u043b\u0430\u0434 \u0421\u0435\u0440\u0433\u0435\u044f \u0420\u044f\u0431\u043e\u0432\u0430<\/u><\/a> \u00ab\u041a\u0430\u043a \u043f\u0440\u0438\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u0440\u043e\u0436\u0430\u0440\u0435\u043d\u043d\u044b\u0438\u0306 MVI \u043f\u043e\u0434 Android\u00bb<a href=\"https:\/\/www.youtube.com\/watch?v=hBkQkjWnAjg\"> <\/a>\u0438 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043e <a href=\"https:\/\/habr.com\/ru\/company\/badoo\/blog\/429728\/\"><u>\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 MVI-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0432 Badoo<\/u><\/a>.<\/p>\n<details class=\"spoiler\">\n<summary>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 MVI<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412\u043a\u0440\u0430\u0442\u0446\u0435, MVI (Model-View-Intent) \u2014 \u044d\u0442\u043e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0439 \u043f\u0430\u0442\u0442\u0435\u0440\u043d, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u0445\u043e\u0434\u0438\u0442 \u0432 \u0441\u0435\u043c\u0435\u0439\u0441\u0442\u0432\u043e \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432 Unidirectional Data Flow \u2014 \u043f\u043e\u0434\u0445\u043e\u0434 \u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0432\u0441\u0451 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0435 \u043e\u0434\u043d\u043e\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c. \u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 MVVM, MVI \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u0430\u043d\u043d\u044b\u0445 (Single source of true \u0438\u043b\u0438 SSOT). MVI \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0442\u0440\u0451\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432: \u0441\u043b\u043e\u044f \u043b\u043e\u0433\u0438\u043a\u0438, \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f (Model); UI-\u0441\u043b\u043e\u044f, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 (View); \u0438 \u043d\u0430\u043c\u0435\u0440\u0435\u043d\u0438\u044f (Intent).<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043a\u043b\u0438\u043a\u043d\u0435\u0442 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 \u00ab\u041e\u0442\u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c\u0441\u044f \u043d\u0430 \u0437\u0430\u044f\u0432\u043a\u0443\u00bb, \u0442\u043e \u043a\u043b\u0438\u043a \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 (Intent), \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435 \u0434\u043b\u044f Model. \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440, \u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u0431\u043d\u043e\u0432\u0438\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430. UI-\u0441\u043b\u043e\u0439 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u043d\u043e\u0432\u044b\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u0441\u043a\u0440\u043e\u0435\u0442 \u043a\u043d\u043e\u043f\u043a\u0443 \u0438 \u043f\u043e\u043a\u0430\u0436\u0435\u0442 \u0442\u0435\u043a\u0441\u0442 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0437\u0430\u044f\u0432\u043a\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0430.<\/p>\n<\/div>\n<\/details>\n<h2>\u041a\u0430\u043a \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0432 \u042e\u043b\u0435<\/h2>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u00ab\u041e\u0442\u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c\u0441\u044f \u043d\u0430 \u0437\u0430\u044f\u0432\u043a\u0443\u00bb, \u043a\u0430\u043a \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u0443 \u043d\u0430\u0441 \u0434\u043e \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f Reduktor. \u0417\u0430\u0440\u0430\u043d\u0435\u0435 \u0443\u0442\u043e\u0447\u043d\u044e, \u0447\u0442\u043e \u043c\u044b \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c RxJava.<\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441-\u043c\u0430\u0440\u043a\u0435\u0440 <code>UIEvent<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043a\u0430\u043a\u043e\u0435-\u043b\u0438\u0431\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435, \u0438 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u044b (\u043e\u0431\u044a\u0435\u043a\u0442\u044b) \u0441\u043e\u0431\u044b\u0442\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u044e\u0442\u0441\u044f \u043e\u0442 <code>UIEvent<\/code>. \u0421\u043b\u043e\u0439 Model \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 Android ViewModel, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0438\u0437\u0432\u043d\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f <code>UIEvent<\/code>. \u0412\u043d\u0443\u0442\u0440\u0438 ViewModel \u0435\u0441\u0442\u044c <code>viewStates: Flowable<\/code> \u2014 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430. \u041d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u043b\u043e\u0439 View.<\/p>\n<details class=\"spoiler\">\n<summary>Intent<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"kotlin\">interface UIEvent  object RespondClick : UIEvent()<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>State<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"kotlin\">data class ServiceDetailViewState(    val isLoading: Boolean,    val isRespondAvailable: Boolean )<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>Model<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"kotlin\">class ServiceDetailViewModel : ViewModel(), Consumer&lt;UIEvent> {     private val viewStateProcessor: BehaviorProcessor&lt;ServiceDetailViewState> = BehaviorProcessor.create()     \/\/ \u0422\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430 \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u044b\u0437\u043e\u0432\u0430    private val currentViewState: ServiceDetailViewState        get() = viewStateProcessor.value ?: ServiceDetailViewState(false, true)     private fun postViewState(vs: ServiceDetailViewState): Unit = viewStateProcessor.onNext(vs)     \/\/ \u041f\u043e\u0442\u043e\u043a \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u044d\u043a\u0440\u0430\u043d\u0430    val viewStates: Flowable&lt;ServiceDetailViewState> = viewStateProcessor.toSerialized()     \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0438\u0437\u0432\u043d\u0435    override fun accept(event: UIEvent) {        when (event) {            is RespondClick -> handleRespondClick()        }    }     \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043a\u043b\u0438\u043a\u0430 \u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430    private fun handleRespondClick() {        someNetworkCall()            .subscribeOn(Schedulers.io())            .observeOn(AndroidSchedulers.mainThread())            .doOnSubscribe { postViewState(currentViewState.copy(isLoading = true)) }            .subscribeBy(                onSuccess = { postViewState(ServiceDetailViewState(isRespondAvailable = false)) },                onError = { postViewState(currentViewState.copy(isLoading = false, isRespondAvailable = true)) }            )    } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>View<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"kotlin\">class ServiceDetailView {     \/\/ ..    \/\/ \u041f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f    viewModel.viewStates.subscribe { state ->        showLoading(state.isLoading)        showRespondButton(state.isRespondAvailable)    }     \/\/ \u041e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f RespondClick \u043f\u043e \u043a\u043b\u0438\u043a\u0443 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443    respondButton.setOnClickListener { viewModel.accept(RespondClick) } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u044b\u0448\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0430 \u0443\u043f\u0440\u043e\u0449\u0451\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u044b\u043b\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u042e\u043b\u044b.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f MVI \u0432 \u042e\u043b\u0435<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412 2018-\u043c \u0433\u043e\u0434\u0443 \u0432 Android \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043f\u043e\u043d\u044f\u0442\u0438\u044f MVVM \u0438 MVP \u0431\u044b\u043b\u0438 \u043d\u0430 \u0441\u043b\u0443\u0445\u0443. \u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 MVVM data-binding \u0431\u044b\u043b \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u043c \u043e\u0442 Google, \u043d\u043e \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0441 \u044d\u0442\u0438\u043c, \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c MVP \u043d\u0430\u0447\u0438\u043d\u0430\u043b\u0430 \u0441\u043f\u0430\u0434\u0430\u0442\u044c. \u041e\u0434\u043d\u0430\u043a\u043e, \u0441\u0435\u0440\u0435\u0431\u0440\u044f\u043d\u043e\u0439 \u043f\u0443\u043b\u0438 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u044b\u043b\u0438 \u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438, \u0438 \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u043a \u0447\u0430\u0441\u0442\u043e \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u044e\u0449\u0438\u043c\u0441\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f\u043c \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432.<\/p>\n<p>\u0427\u0442\u043e \u043d\u0435 \u0442\u0430\u043a \u0441 MVP?<\/p>\n<p>\u0412 MVP \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0443\u0434\u0430\u0432\u0430\u043b\u043e\u0441\u044c \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 Presenter, \u043d\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 View. \u042d\u0442\u043e \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u0435\u043c, \u0447\u0442\u043e \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043d\u0435\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432, \u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u044b \u0438\u043c\u0435\u043d\u043d\u043e \u043a \u044d\u043a\u0440\u0430\u043d\u0443 (\u0438\u043b\u0438 \u0435\u0433\u043e \u0447\u0430\u0441\u0442\u0438).<\/p>\n<p>\u0410 \u0447\u0442\u043e \u0441 MVVM?<\/p>\n<p>\u0412 MVVM \u043d\u0430 data-binding \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0440\u0430\u0437\u043d\u044b\u0435 \u043a\u0443\u0441\u043a\u0438 \u044d\u043a\u0440\u0430\u043d\u0430 \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u043b\u0438\u0441\u044c \u043a \u0440\u0430\u0437\u043d\u044b\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u043c \u0432\u043e ViewModel. \u041e \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438 \u043e\u0431\u044b\u0447\u043d\u043e \u043d\u0435 \u0437\u0430\u0434\u0443\u043c\u044b\u0432\u0430\u043b\u0438\u0441\u044c, \u0447\u0442\u043e \u043c\u043e\u0433\u043b\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u043a \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u043c c UX. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u0430\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0432 \u043a\u0430\u043a\u043e\u043c-\u043d\u0438\u0431\u0443\u0434\u044c \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u0431\u043b\u043e\u043a\u0435, \u0430 \u043d\u0438\u0436\u043d\u0438\u0439 \u0431\u043b\u043e\u043a \u0443\u0436\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0443\u044e \u043e\u0448\u0438\u0431\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043d\u0430\u0447\u0438\u043d\u0430\u043b \u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e.<\/p>\n<p>\u0418 \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u0432\u043e\u043f\u0440\u043e\u0441 &#8212; \u0447\u0442\u043e \u0436\u0435 \u0442\u0430\u043a\u043e\u0435 \u00abModel\u00bb \u0432 MVP\/MVVM? \u041e\u0431\u044b\u0447\u043d\u043e \u0432 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u043a\u043e\u0434\u0430\u00a0 \u043a\u043b\u0430\u0441\u0441 \u00abModel\u00bb \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u043b, \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u043b\u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438. \u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438? \u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0432\u043e ViewModel\/Presenter?<\/p>\n<p>\u0412 2018-\u043c \u043d\u0430\u043c \u043f\u043e\u043f\u0430\u043b\u0430\u0441\u044c \u0441\u0435\u0440\u0438\u044f \u0441\u0442\u0430\u0442\u0435\u0439 \u043e\u0442 Hannes Dorfman, \u0433\u0434\u0435 \u043e\u043d \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043b \u043f\u0440\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 MVI (ViewState, \u043c\u0435\u0442\u043e\u0434 render(), reducer, intent() \u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f) \u0438 \u0434\u0435\u043b\u0430\u043b \u043e\u0441\u043e\u0431\u044b\u0439 \u0430\u043a\u0446\u0435\u043d\u0442 \u043d\u0430 \u0442\u043e\u043c, \u0447\u0442\u043e \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u043e\u043b\u0436\u043d\u0430 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0445. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0442\u043e\u0439 \u0441\u0435\u0440\u0438\u0438 \u0441\u0442\u0430\u0442\u0435\u0439 \u043d\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043b\u0441\u044f (\u0430\u0432\u0442\u043e\u0440 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u043b \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438), \u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0431\u0449\u0435\u0439 \u043a\u0430\u0440\u0442\u0438\u043d\u0435 \u043c\u043e\u0436\u043d\u043e <a href=\"http:\/\/hannesdorfmann.com\/android\/model-view-intent\">\u0437\u0434\u0435\u0441\u044c<\/a>. \u0421\u0430\u043c\u043e\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u2014 Presenter \u0432 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u043a\u043e\u0434\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u043b, \u0431\u044b\u043b\u0430 ViewModel.<\/p>\n<p>\u0412 \u044d\u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f \u0432 Android-\u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u00ab\u042e\u043b\u044b\u00bb \u0441\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u043f\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u2014 \u0438\u0442\u043e\u0433\u043e \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u0441\u0442\u0430\u043b\u043e \u0430\u0436 \u0446\u0435\u043b\u044b\u0445 \u0442\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0432\u043c\u0435\u0441\u0442\u043e 2-\u0445. \ud83d\ude42 \u041f\u0440\u0438 \u0430\u043c\u0431\u0438\u0446\u0438\u043e\u0437\u043d\u043e\u043c \u043f\u043b\u0430\u043d\u0435 \u043f\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0443 \u0438 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0443 \u0444\u0438\u0447 \u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u043d\u0430 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433, \u0441\u0442\u0430\u043b\u043e \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0442\u044c \u043d\u0430\u043c \u043d\u0438\u0437\u043a\u0438\u0439 time to market, \u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c\u043e\u0435 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u043a\u043e\u0434\u0430 \u0438 \u043d\u0435\u0432\u044b\u0441\u043e\u043a\u0438\u0439 \u043f\u043e\u0440\u043e\u0433 \u0432\u0445\u043e\u0434\u0430. <\/p>\n<p>\u041e\u0442\u0441\u044e\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0432\u044b\u0434\u0435\u043b\u0438\u0442\u044c <strong>\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f<\/strong>:<\/p>\n<ol>\n<li>\n<p>\u041f\u0440\u0438\u043c\u0435\u043d\u0438\u043c\u043e\u0441\u0442\u044c \u0434\u043b\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432. TTM \u0441\u043e\u043a\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0437\u0430 \u0441\u0447\u0451\u0442 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443 \u043f\u0440\u043e\u0449\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f, \u0442\u0430\u043a \u043a\u0430\u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0444\u0438\u0447\u0438, \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u043f\u043e \u043e\u0434\u043d\u043e\u043c\u0443 \u0448\u0430\u0431\u043b\u043e\u043d\u0443;<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u0441\u0435\u0433\u043e \u043a\u043e\u0434\u0430, \u0447\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u043e\u0436\u043d\u043e (\u043c\u043e\u0434\u0435\u043b\u0438\/\u0441\u043e\u0431\u044b\u0442\u0438\u044f\/\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438\/use-case, \u0438 \u0434\u0440.);<\/p>\n<\/li>\n<li>\n<p>Unidirectional Data Flow \u2014 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043f\u043e \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u043e \u0432 \u043a\u0430\u0436\u0434\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0441\u043e\u043a\u0440\u0430\u0449\u0430\u0435\u043c \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u043e\u0442\u043b\u0430\u0434\u043a\u0443;<\/p>\n<\/li>\n<li>\n<p>Single Source of Truth \u2014 \u0435\u0441\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435* (\u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\u0445 \u043d\u0438\u0436\u0435), \u0430 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u2014 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u043d\u0430\u044f \u043e\u0442 \u043d\u0435\u0433\u043e. \u0418\u0441\u043a\u0430\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u044d\u0442\u043e\u0442 source of truth. UI \u043b\u043e\u0433\u0438\u043a\u0430 \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442, \u0430 \u043b\u0438\u0448\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442 \u043f\u0440\u0438\u0448\u0435\u0434\u0448\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u2014<code>render(state: ViewState)<\/code>;<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u043f\u0430\u0440\u0430\u0434\u0438\u0433\u043c\u044b: \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u044d\u043a\u0440\u0430\u043d\u044b \u0447\u0430\u0441\u0442\u043e \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0438\u0437-\u0437\u0430 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043b\u0435\u043d\u0442\u0430 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442 \u0444\u0438\u043b\u044c\u0442\u0440\u044b. \u041f\u043e\u0438\u0441\u043a \u2014 \u043f\u043e \u0432\u0432\u043e\u0434\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438\u043b\u0438 \u0441\u0430\u0434\u0436\u0435\u0441\u0442\u0430. \u042d\u043a\u0440\u0430\u043d \u0437\u0430\u043a\u0430\u0437\u0430 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u0437\u0430\u043a\u0430\u0437\u0430 \u0441 \u043f\u0443\u0448\u0430 \u0438\u043b\u0438 \u043f\u043e \u0432\u0435\u0431-\u0441\u043e\u043a\u0435\u0442\u0443. \u041c\u044b \u043e\u0436\u0438\u0434\u0430\u0435\u043c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f (\u0438\u043b\u0438 \u0441\u0435\u0440\u0438\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439) \u0438 \u0440\u0435\u0430\u0433\u0438\u0440\u0443\u0435\u043c \u043d\u0430 \u044d\u0442\u043e.<\/p>\n<\/li>\n<\/ol>\n<p>MVI \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u043b \u043f\u043e\u0434 \u044d\u0442\u043e \u043a\u0430\u043a \u043d\u0435\u043b\u044c\u0437\u044f \u043b\u0443\u0447\u0448\u0435. \u041e\u0434\u043d\u0430\u043a\u043e \u043c\u044b \u043f\u0435\u0440\u0435\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 Hannes\u2019\u0430 \u0438\u0437 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0441\u043e\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439. \u0410 \u0438\u043c\u0435\u043d\u043d\u043e:<\/p>\n<ol>\n<li>\n<p>\u041c\u044b \u043d\u0435 \u0441\u0442\u0430\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0432\u043e ViewModel \u0441\u043f\u0438\u0441\u043e\u043a <code>Observable&lt;UserIntent><\/code> \u0438 \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u043e\u0439. \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e ViewModel \u0441\u0442\u0430\u043b\u0430 <code>Consumer&lt;UIEvent><\/code>, \u0433\u0434\u0435 <code>UIEvent<\/code> \u2013 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 (\u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e <code>sealed class<\/code>), \u0432\u0441\u0435\u0433\u043e \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u043b\u043e \u0432\u043e View: \u044d\u0442\u043e \u0438 \u043a\u043b\u0438\u043a\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0438 \u0441\u0442\u0430\u0440\u0442 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f, \u0438 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430, \u0438 \u043e\u0442\u0432\u0435\u0442\u044b \u043e\u0442 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 sdk (\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u0432 <code>onActivityResult())<\/code>. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c,\u00a0 View \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u0441 ViewModel \u0447\u0435\u0440\u0435\u0437 \u043e\u0434\u0438\u043d \u043c\u0435\u0442\u043e\u0434 \u2014<code>consume()<\/code> (\u0438\u043b\u0438 <code>accept()<\/code>, \u0435\u0441\u043b\u0438 \u043c\u044b \u0431\u0435\u0440\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 RxJava);<\/p>\n<pre><code class=\"kotlin\">override fun accept(event: UIEvent) {    when (event) {        is FilterUiEvent.Init -> handleInit(event)        is BaseUiEvent.SaveState -> handleSaveState(event)        is BaseUiEvent.RestoreState ->handleRestoreState(event) ... }<\/code><\/pre>\n<\/li>\n<li>\n<p>View \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043e\u0434\u0438\u043d \u043c\u0435\u0442\u043e\u0434 \u2014<code>render(state: ViewState)<\/code>. View \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u044f, \u043a\u0430\u043a\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u0440\u0438\u0448\u043b\u043e, \u0442\u0430\u043a\u043e\u0435 \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f. ViewState \u043c\u044b \u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0438 \u0447\u0435\u0440\u0435\u0437 sealed-\u043a\u043b\u0430\u0441\u0441\u044b, \u0438 \u0434\u0435\u043b\u0430\u043b\u0438 \u0438\u0445 \u00ab\u043f\u043b\u043e\u0441\u043a\u0438\u043c\u0438\u00bb (\u0444\u043b\u0430\u0436\u043a\u0438 \u043e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435, \u043e\u0448\u0438\u0431\u043a\u0435, \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043b\u0435\u0436\u0430\u0442 \u0432 \u043e\u0434\u043d\u043e\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u0435), \u2014\u00a0 \u0432\u0441\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0440\u0430\u0431\u043e\u0447\u0438\u0435, \u043e\u0433\u0440\u043e\u043c\u043d\u044b\u0445 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432 \u0443 \u043a\u0430\u043a\u043e\u0433\u043e-\u0442\u043e \u043d\u0435\u0442;<\/p>\n<\/li>\n<li>\n<p>Reducer \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u0437\u0430\u043c\u0435\u043d\u044f\u043b\u043e \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435: <code>data class copy()<\/code>. \u041e\u0434\u043d\u0430\u043a\u043e \u0434\u043b\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0441 \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>reduce(state: ViewState, event: UIEvent)<\/code> \u043d\u0435 \u043b\u0435\u043d\u0438\u043b\u0438\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c;<\/p>\n<\/li>\n<li>\n<p>ViewModel \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0430 <code>states: Flowable&lt;ViewState><\/code>. \u0412\u043d\u0443\u0442\u0440\u0438 \u044d\u0442\u043e \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u0431\u044b\u043b\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u0447\u0435\u0440\u0435\u0437 <code>BehaviorProcessor&lt;ViewState>;<\/code><\/p>\n<\/li>\n<li>\n<p>\u0418\u0437 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0441\u043e\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439: ViewModel \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0430 <code>routeEvents: Flowable&lt;RouteEvent><\/code> \u0438 <code>serviceEvent: Flowable&lt;ServiceEvent>.<\/code>\u0421\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 <code>Router: Consumer&lt;RouteEvent><\/code> \u2014 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0435\u043c \u043f\u043e\u0442\u043e\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438, \u0438\u0437 \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0440\u043e\u0443\u0442\u0435\u0440\u043e\u0432 \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044f \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. ServiceEvent \u0441\u043b\u0443\u0436\u0438\u0442 \u0434\u043b\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u00abfire and forget\u00bb, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043d\u0435 \u0445\u043e\u0442\u0438\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u043e ViewState \u2013 \u043f\u043e\u043a\u0430\u0437\u044b \u0442\u0443\u043b\u0442\u0438\u043f\u043e\u0432, toast\u2019\u043e\u0432, \u0434\u0438\u0430\u043b\u043e\u0433\u0438-\u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438 \u0438 \u0442\u043e\u043c\u0443 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435;<\/p>\n<p><strong><em>\u0414\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440:<br \/>\u041c\u044b \u043d\u0435 \u043f\u0440\u0438\u0437\u044b\u0432\u0430\u0435\u043c \u0432\u0430\u0441 \u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a. \u0415\u0441\u043b\u0438 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u0445\u043e\u0434 (\u043d\u0430\u0432\u0438\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c) \u043f\u043e State \u0438\u043b\u0438 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u043e\u043a\u0430\u0437 toast, \u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 state, \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043b\u0438\u0448\u043d\u0438\u0445 \u043f\u043e\u0434\u043f\u0438\u0441\u043e\u043a. \u0412 \u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u043d\u0446\u043e\u0432, \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u043d\u0435 \u0430\u043a\u0430\u0434\u0435\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435, \u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0438 \u0434\u0435\u0448\u0451\u0432\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435<\/em><\/strong><\/p>\n<\/li>\n<li>\n<p>ViewModel \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u044f\u0432\u043b\u044f\u043b\u0430\u0441\u044c \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0435\u043d\u0438\u0435\u043c \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438, \u0438, \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0430\u0441\u044c \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0431\u044b\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0439 \u043d\u0430 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a Android;<\/p>\n<\/li>\n<li>\n<p>ViewModel \u043e\u0431\u0440\u0430\u0449\u0430\u043b\u0430\u0441\u044c \u043a repository, mapper\u2019\u0430\u043c, \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043b\u0430 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438, \u043c\u0435\u043d\u044f\u043b\u0430 \u0442\u0440\u0435\u0434\u044b, \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043b\u0430 \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438 \u043e\u0442\u0441\u044b\u043b\u0430\u043b\u0430 \u0435\u0433\u043e \u043d\u0430 UI;<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f,\u00a0 \u0434\u043b\u044f \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u0441\u0440\u0430\u0437\u0443 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u043b\u0438 DiffUtil, \u0434\u043e\u0431\u0438\u0432\u0430\u044f\u0441\u044c \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u043d\u0430 UI.<\/p>\n<\/li>\n<\/ol>\n<p><strong>\u0427\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0432 \u0438\u0442\u043e\u0433\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438:<\/strong><\/p>\n<ol>\n<li>\n<p>\u0421\u0442\u0430\u043b\u043e \u043f\u0440\u043e\u0449\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438. \u041d\u0435\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438 \u2014 \u0441\u043c. ViewModel. \u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u0448\u043b\u0438, \u043d\u043e \u043a\u0440\u0438\u0432\u043e\u0439 UI \u2014 \u0441\u043c. View. \u041a\u0440\u0438\u0432\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u2014 \u0441\u043c. \u043b\u043e\u0433\u0438 \u043f\u0440\u0438 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438\/\u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 state\u2019\u0430 \u0434\u043b\u044f View;<\/p>\n<\/li>\n<li>\n<p>\u042d\u0442\u043e \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u0438 \u043a \u043a\u043b\u0430\u0441\u0441\u0430\u043c \u0441 \u0440\u0430\u0437\u043d\u043e\u0439 \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c\u044e, \u0432\u0435\u0434\u044c \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0430\u043a\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u0434\u0430\u0442\u044c \u044d\u0442\u043e \u0440\u0430\u0437\u043d\u044b\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c \u0434\u043b\u044f \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0422\u0422\u041c;<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u0438\u0441<\/p>\n<\/li>\n<\/ol>\n<\/div>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-337778","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/337778","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=337778"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/337778\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=337778"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=337778"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=337778"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}