如何使用Java(而不是Kotlin)在Android中使用RxJava管理状态

如何使用Java(而不是Kotlin)在Android中使用RxJava管理状态,android,rx-java2,Android,Rx Java2,我正试图根据杰克·沃顿(Jake Wharton)的以下演讲开发一个Android应用程序 The State of Managing State with RxJava 21 March 2017 – Devoxx (San Jose, CA, USA) Jake承诺了第2部分和/或GITHUB示例,但我找不到(如果确实存在) 在较高的层次上,我可以理解/理解上述大部分谈话 不过,我有以下问题 我可以看到使用UiEvent、UiModel、Action和Result是如何将关注点分开的 我感

我正试图根据杰克·沃顿(Jake Wharton)的以下演讲开发一个Android应用程序

The State of Managing State with RxJava
21 March 2017 – Devoxx (San Jose, CA, USA)
Jake承诺了第2部分和/或GITHUB示例,但我找不到(如果确实存在)

在较高的层次上,我可以理解/理解上述大部分谈话

不过,我有以下问题

我可以看到使用UiEvent、UiModel、Action和Result是如何将关注点分开的

我感到困惑的是:-

幻灯片194上的图表显示了观察物的“流/流”,如下所示:

Android Device -----> Observable<UiEvent> -----> <application code> -----> Observable<Action>  -----> {Backend}
{Backend}      -----> Observable<Result>  -----> <application code> -----> Observable<UiModel> -----> Android Device
“我的活动”一显示,我就会收到以下日志:-

2018-10-09 14:22:33.310 D/MainActivity: report() called with: model = [UiModel{isProgress=false, message='null', isSuccess=false, data=null}]
2018-10-09 14:22:33.311 E/MainActivity: scan() state = UiModel{isProgress=false, message='null', isSuccess=false, data=null} result = SearchResult{lifecycle=IN_FLIGHT, data=null, errorMessage='null'}
2018-10-09 14:22:33.311 D/MainActivity: report() called with: model = [UiModel{isProgress=true, message='null', isSuccess=false, data=null}]
2018-10-09 14:22:33.313 E/MainActivity: scan() state = UiModel{isProgress=true, message='null', isSuccess=false, data=null} result = CharacterResult{lifecycle=IN_FLIGHT, data=null, errorMessage='null'}
2018-10-09 14:22:33.313 D/MainActivity: report() called with: model = [UiModel{isProgress=true, message='null', isSuccess=false, data=null}]
2018-10-09 14:22:33.313 E/MainActivity: scan() state = UiModel{isProgress=true, message='null', isSuccess=false, data=null} result = FilmResult{lifecycle=IN_FLIGHT, data=null, errorMessage='null'}
2018-10-09 14:22:33.313 D/MainActivity: report() called with: model = [UiModel{isProgress=true, message='null', isSuccess=false, data=null}]
2018-10-09 14:55:19.463 E/MainActivity: scan() state = UiModel{isProgress=false, message='null', isSuccess=true, data=com.test.model.JsonData@5e0b6f1} result = FilmResult{lifecycle=LANDED_SAFELY, data=com.test.model.JsonData@8ae4d86, errorMessage='null'}
2018-10-09 14:55:19.463 D/MainActivity: report() called with: model = [UiModel{isProgress=false, message='null', isSuccess=true, data=com.test.model.JsonData@8ae4d86}]
我猜是由于我的
.startWith()
语句,我在飞行中得到了这些
结果

当我单击搜索按钮或在编辑文本视图中输入任何文本时,我会看到以下日志:-

2018-10-09 14:22:33.310 D/MainActivity: report() called with: model = [UiModel{isProgress=false, message='null', isSuccess=false, data=null}]
2018-10-09 14:22:33.311 E/MainActivity: scan() state = UiModel{isProgress=false, message='null', isSuccess=false, data=null} result = SearchResult{lifecycle=IN_FLIGHT, data=null, errorMessage='null'}
2018-10-09 14:22:33.311 D/MainActivity: report() called with: model = [UiModel{isProgress=true, message='null', isSuccess=false, data=null}]
2018-10-09 14:22:33.313 E/MainActivity: scan() state = UiModel{isProgress=true, message='null', isSuccess=false, data=null} result = CharacterResult{lifecycle=IN_FLIGHT, data=null, errorMessage='null'}
2018-10-09 14:22:33.313 D/MainActivity: report() called with: model = [UiModel{isProgress=true, message='null', isSuccess=false, data=null}]
2018-10-09 14:22:33.313 E/MainActivity: scan() state = UiModel{isProgress=true, message='null', isSuccess=false, data=null} result = FilmResult{lifecycle=IN_FLIGHT, data=null, errorMessage='null'}
2018-10-09 14:22:33.313 D/MainActivity: report() called with: model = [UiModel{isProgress=true, message='null', isSuccess=false, data=null}]
2018-10-09 14:55:19.463 E/MainActivity: scan() state = UiModel{isProgress=false, message='null', isSuccess=true, data=com.test.model.JsonData@5e0b6f1} result = FilmResult{lifecycle=LANDED_SAFELY, data=com.test.model.JsonData@8ae4d86, errorMessage='null'}
2018-10-09 14:55:19.463 D/MainActivity: report() called with: model = [UiModel{isProgress=false, message='null', isSuccess=true, data=com.test.model.JsonData@8ae4d86}]
为什么我看不到“飞行中”和“安全着陆”

我只能“安全着陆”

我在UI事件->操作->结果->UI模型之间进行转换的方法是否接近J沃顿先生所描述的

我哪里出错了

更新(二)

我的错误是没有在
.flatmap()
操作中包含所有下游接收

澄清

UI事件-->Action-->Result-->UI模型的这种模式是否仍然适用于没有“后端”的情况?e、 g.主屏幕可以向用户提供许多选项(按钮),以导航到应用程序中的较低级别屏幕。UI事件将是“Button Click”,UI模型将返回与
startActivity()
方法调用相关联的活动类

如何将登录屏幕的UI输入事件合并到一个UI事件流中,其中有两个EditText字段(用户名和密码)和一个登录按钮。 我希望按钮单击UI事件包含输入的用户名和用户密码。如果我使用RxBinding处理EditText并单击登录按钮,我看不出如何将这三个观察值组合到我的UI事件流中,并验证EditText,以确保它们输入了数据,然后将用户输入的数据传递到我的后端登录API(例如,可能是Google登录)

(我在添加评论,但太长了)

我无法帮助杰克进行演讲等等。但是关于你的最后一个问题:

这个UI事件模式-->操作-->结果-->UI模型吗 仍然适用于没有“后端”的情况吗

确实如此,只是后端是您的应用程序状态存储库

在这种体系结构中,应用程序应该只有一个真实的位置:后端、本地数据库、两者的组合或任何适合您用例的解决方案


考虑到这一点,您的操作流应该通过调用后端、将更改发布到数据库或在共享设置中写入元素来修改状态。同样,状态的更改应该触发向流发送结果


具体细节将取决于您使用什么作为应用程序的真实来源。

数据流和状态

它主要使用Paco和Jake Wharton RxState的想法,并添加了一些其他内容

  • 使用UiEvent→ 行动、结果→ 为变压器建模并始终运行 在RxJava操作符的帮助下在单个状态上(形成单个 事件流,然后根据其类型使用 不同的转换器,然后再次合并结果,修改 状态,然后最终在UI上呈现它
  • 或者不使用变压器,让它更“简单”
下面是不使用任何转换器的“完整”视图模型代码:

class SomeViewModel(private val someRepository: SomeRepository): ViewModel() {

    val uiEvents: PublishSubject<UiEvent> = PublishSubject.create()
    val outputState: MutableLiveData<Result<UiState>> = MutableLiveData()

    init {
        uiEvents.subscribe {
            when (it) {
                    is FirstEvent -> getSomeResultsFromRepo(it.id)
                    is SecondEvent -> handleSecondEvent()
                }
        }
    }

    fun getSomeResultsFromRepo(id: String) {
        someRepository.getResult(id)
                .map { UiState(it) }
                .map { Result.success(it) }
                .startWith(Result.loading())
                .onErrorReturn { handleError(it) }
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({
                    outputState.postValue(it)
                })
    }

    fun handleSecondEvent() {
        /* do something here */
        someRepository.getSomeOtherResult()
                .map { UiState(it) }
                .map { Result.success(it) }
                .startWith(Result.loading())
                .onErrorReturn { handleError(it) }
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({
                    outputState.postValue(it)
                })
    }

    private fun handleError(error: Throwable): Result<UiState> {
        return if (error is RetrofitException) {
            when (error.kind) {
                RetrofitException.Kind.NETWORK -> Result.failure(NetworkError(error))
                RetrofitException.Kind.HTTP -> Result.failure(ServerError(error))
                RetrofitException.Kind.UNEXPECTED -> Result.failure(UnknownError(error))
                else -> Result.failure(UnknownError(error))
            }
        } else {
            Result.failure(UnknownError(error))
        }
    }

    class Factory @Inject constructor(private val someRepo: SomeRepository) : ViewModelProvider.Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            @Suppress("UNCHECKED_CAST")
            return SomeViewModel(someRepo) as T
        }
    }
}
class-SomeViewModel(私有val-someRepository:someRepository):ViewModel(){
val uiEvents:PublishSubject=PublishSubject.create()
val outputState:MutableLiveData=MutableLiveData()
初始化{
uiEvents.subscribe{
什么时候{
is FirstEvent->getSomeResultsFromRepo(it.id)
是SecondEvent->handleSecondEvent()
}
}
}
fun getSomeResultsFromRepo(id:String){
someRepository.getResult(id)
.map{UiState(it)}
.map{Result.success(it)}
.startWith(Result.loading())
.onErrorReturn{handleError(it)}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.订阅({
outputState.postValue(it)
})
}
乐趣无穷{
/*在这里做点什么*/
someRepository.getSomeOtherResult()的
.map{UiState(it)}
.map{Result.success(it)}
.startWith(Result.loading())
.onErrorReturn{handleError(it)}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.订阅({
outputState.postValue(it)
})
}
私人娱乐手柄错误(错误:可丢弃):结果{
返回if(错误为异常){
何时(error.kind){
更新异常.Kind.NETWORK->Result.failure(NetworkError(error))
inversionException.Kind.HTTP->Result.failure(ServerError(error))
InversionException.Kind.UNEXPECTED->Result.failure(未知错误)
else->Result.failure(未知错误(错误))
}
}否则{
结果.失败(未知错误(错误))
}
}
类Factory@Inject构造函数(私有val someRepo:SomeRepository):ViewModelProvider.Factory{
覆盖f
2018-10-09 14:55:19.463 E/MainActivity: scan() state = UiModel{isProgress=false, message='null', isSuccess=true, data=com.test.model.JsonData@5e0b6f1} result = FilmResult{lifecycle=LANDED_SAFELY, data=com.test.model.JsonData@8ae4d86, errorMessage='null'}
2018-10-09 14:55:19.463 D/MainActivity: report() called with: model = [UiModel{isProgress=false, message='null', isSuccess=true, data=com.test.model.JsonData@8ae4d86}]
class SomeViewModel(private val someRepository: SomeRepository): ViewModel() {

    val uiEvents: PublishSubject<UiEvent> = PublishSubject.create()
    val outputState: MutableLiveData<Result<UiState>> = MutableLiveData()

    init {
        uiEvents.subscribe {
            when (it) {
                    is FirstEvent -> getSomeResultsFromRepo(it.id)
                    is SecondEvent -> handleSecondEvent()
                }
        }
    }

    fun getSomeResultsFromRepo(id: String) {
        someRepository.getResult(id)
                .map { UiState(it) }
                .map { Result.success(it) }
                .startWith(Result.loading())
                .onErrorReturn { handleError(it) }
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({
                    outputState.postValue(it)
                })
    }

    fun handleSecondEvent() {
        /* do something here */
        someRepository.getSomeOtherResult()
                .map { UiState(it) }
                .map { Result.success(it) }
                .startWith(Result.loading())
                .onErrorReturn { handleError(it) }
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({
                    outputState.postValue(it)
                })
    }

    private fun handleError(error: Throwable): Result<UiState> {
        return if (error is RetrofitException) {
            when (error.kind) {
                RetrofitException.Kind.NETWORK -> Result.failure(NetworkError(error))
                RetrofitException.Kind.HTTP -> Result.failure(ServerError(error))
                RetrofitException.Kind.UNEXPECTED -> Result.failure(UnknownError(error))
                else -> Result.failure(UnknownError(error))
            }
        } else {
            Result.failure(UnknownError(error))
        }
    }

    class Factory @Inject constructor(private val someRepo: SomeRepository) : ViewModelProvider.Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            @Suppress("UNCHECKED_CAST")
            return SomeViewModel(someRepo) as T
        }
    }
}