gpt4 book ai didi

java - 在没有 Mosby 的 Android 中实现 MVI 架构

转载 作者:太空宇宙 更新时间:2023-11-04 09:49:28 28 4
gpt4 key购买 nike

我正在尝试在 Android 中实现 MVI 架构,但不想使用 Mosby 库。我想先学习基础知识。

我正在构建一个示例应用程序,当我按下按钮时, TextView 中的文本会发生变化(最初文本是其他内容)。这是 MainActivity 和 MainPresenter 的代码。

class MainActivity : AppCompatActivity(), MainContract.View {

lateinit var mPresenter: MainContract.Presenter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mPresenter = MainPresenter()
mPresenter.attachPresenter(this)
bind()
}

@SuppressLint("CheckResult")
private fun bind() {
mPresenter.states().subscribe({ state ->
render(state)
}, {
Log.e("error", "Error is: ", it)
it.printStackTrace()
})
mPresenter.addIntents(intents())
}

override fun intents(): Observable<MainIntent> {
return Observable.merge(
initialIntent(),
clickIntent()
)
}

override fun render(state: MainViewState) {
btn_show.isEnabled = state.isEnabledButton
helloWorldTextView.text = state.message
loadingIndicator.visibility = if (state.isLoading) View.VISIBLE else View.GONE
}

private fun initialIntent(): Observable<MainIntent.InitialIntent> = Observable.just(MainIntent.InitialIntent)

private fun clickIntent(): Observable<MainIntent.ClickIntent> {
return btn_show.clicks().map { MainIntent.ClickIntent("Eureka") }
}


}



class MainPresenter : MainContract.Presenter {

private val intentsSubject: PublishSubject<MainIntent> = PublishSubject.create()

override fun states(): Observable<MainViewState> {
return statesObservable
}

private lateinit var view: MainContract.View

override fun attachPresenter(view: MainContract.View) {
this.view = view
}

@SuppressLint("CheckResult")
override fun addIntents(intents: Observable<MainIntent>) {
intents.subscribe(intentsSubject)
}

private val reducer =
BiFunction { previousState: MainViewState, result: MainResult ->
when (result) {
is MainResult.InitialResult.InFlight -> previousState.copy(
isLoading = true,
message = "Initial Result",
isEnabledButton = false
)
is MainResult.InitialResult.Success -> previousState.copy(
isLoading = true,
message = "Initial Success",
isEnabledButton = true
)
is MainResult.InitialResult.Error -> previousState.copy(
isLoading = false,
message = "Error Initially",
isEnabledButton = true
)

is MainResult.ClickedResult.Success -> previousState.copy(
isLoading = false,
message = System.currentTimeMillis().toString(),
isEnabledButton = true
)
is MainResult.ClickedResult.Error -> previousState.copy(
isLoading = false,
message = "Error Clicked",
isEnabledButton = true
)
is MainResult.ClickedResult.InFlight -> previousState.copy(
isLoading = true,
message = "Clicked In Flight",
isEnabledButton = false
)
}
}

private fun actionFromIntent(intent: MainIntent): MainAction {
if (intent is MainIntent.InitialIntent) {
return MainAction.InitialAction
} else if (intent is MainIntent.ClickIntent) {
return MainAction.ClickedAction("Hello")
} else {
return MainAction.InitialAction
}
}

private var actionProcessor: ObservableTransformer<MainAction, MainResult> = ObservableTransformer { actions ->
actions.publish { shared ->
Observable.merge<MainResult>(
shared.ofType(MainAction.InitialAction::class.java).compose(initialActionProcessor),
shared.ofType(MainAction.ClickedAction::class.java).compose(clickActionProcessor)
)
}
}

private val initialActionProcessor =
ObservableTransformer<MainAction.InitialAction, MainResult.InitialResult> { action: Observable<MainAction.InitialAction> ->
action.switchMap {
Observable.just("hello initially")
.map { MainResult.InitialResult.Success(it) }
.cast(MainResult.InitialResult::class.java)
.onErrorReturn { MainResult.InitialResult.Error(it.message!!) }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.startWith { MainResult.InitialResult.InFlight }
}
}

private val clickActionProcessor =
ObservableTransformer<MainAction.ClickedAction, MainResult.ClickedResult> { action: Observable<MainAction.ClickedAction> ->
Observable.just("Click").map { message ->
MainResult.ClickedResult.Success(message)
}.cast(MainResult.ClickedResult::class.java)
.onErrorReturn { MainResult.ClickedResult.Error("Error") }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.startWith { MainResult.ClickedResult.InFlight }
}

private val statesObservable: Observable<MainViewState> = compose()

private fun compose(): Observable<MainViewState> {
return intentsSubject
.map {
actionFromIntent(it)
}
.compose(actionProcessor)
.scan(MainViewState.idle(), reducer)
.distinctUntilChanged()
.replay(1)
.autoConnect(0)
}


}

问题是只触发了 Inital 事件,没有其他事件。该代码不响应点击,渲染仅最初被调用一次。

此外,如果我从 actionProcessors 代码中删除 startWith{} ,则会响应点击,但只会响应一次。之后,什么也没有发生。

有人发现代码有问题吗?一段时间以来我一直在努力解决这个问题。

最佳答案

我之前的回复:

这不是您问题的直接答案。但如果您实现以下内容,您可能不会遇到您实际询问的问题,并且您将获得更简单的 MVI 解决方案。

您可能尝试合并 https://speakerdeck.com/jakewharton/the-state-of-managing-state-with-rxjava-devoxx-us-2017 , http://hannesdorfmann.com/android/mosby3-mvi-1https://medium.com/@oldergod/managing-state-with-rxjava-b0798a6c5757想法。

看这里:https://proandroiddev.com/taming-state-in-android-with-elm-architecture-and-kotlin-part-1-566caae0f706 - 更简单了。第 1 部分和第 2 部分应该足够了。

我尝试了第一种方法,但因最初的复杂性而被拒绝。在第二种方法中,您没有操作、 Intent 、结果,而是消息。推理起来更简单。

还有新的 MVI 类(class) - 但尚未检查。

当前方法:

我尝试提到Elm架构,但它并不完整。至少有两个问题:

  1. 同一时刻只有一个请求可以通过队列。一些 RxJava应该可以解决这个问题(groupBy 有 2 个流:ui、background可能)。
  2. 并行请求会更新相同的状态,因此您应该区分 UiState 内的 DataStates。因此 UI 的不同部分有不同的状态。

在编写实际修复程序之前,我们意识到,这不是 ATM 的出路:宣布的可组合项可以实现 MVI 技巧:将数据平滑且精确地转换到 UI 的特定部分。

免责声明:版主删除了我的答案,这是实际答案。更重要的是,我的评论转移到评论被删减,这使它看起来未完成。这就是为什么这篇文章再次出现的原因。亲爱的版主,阅读完后,您可以删除免责声明,谢谢:)

关于java - 在没有 Mosby 的 Android 中实现 MVI 架构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54969588/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com