反应性流处理用户输入和网络的模式

时间:2018-09-10 16:11:05

标签: android kotlin retrofit2 rx-java2

我正在使用RxKotlin构建我最新的Android应用程序,但遇到一个熟悉的问题:如何以类似Rx的方式处理网络错误。

我有一个针对TextView的搜索字词流,如下所示:

searchBar
  .queryTextObservable()
  .debounce(500, TimeUnit.MILLISECONDS)
  .map { it.trim() }
  .filter { it.isNotBlank() }
  .observeOn(Schedulers.io())

这是侦听文本输入更改的一种有用方法,因此,我随后扩展代码以将准备好的文本馈送到网络请求中(使用带有RxJava扩展名的Retrofit库)以搜索:

searchBar
  .queryTextObservable()
  .debounce(500, TimeUnit.MILLISECONDS)
  .map { it.trim() }
  .filter { it.isNotBlank() }
  .observeOn(Schedulers.io())
  .switchMap { search(it) }
  .observeOn(AndroidSchedulers.mainThread())
  .subscribeOn(AndroidSchedulers.mainThread())
  .subscribe(...)

出现网络错误时会发生问题-我的整个订阅都被取消了。似乎我有一些方法可以管理故障,但是似乎没有一个很干净:

  • 文本输入完成后,内部有一个可观察到的内部信号,
  • 使用onErrorResumeNext并传递哨兵值

这显然不是详尽无遗的,但是什么是合适的模式来适当地处理网络错误,同时保留来自搜索栏的用户输入流(以及有用性)?

1 个答案:

答案 0 :(得分:0)

如果您查看提供单向数据流(例如MVI)的反应模式,则使用onErrorReturn这样的运算符是一种非常标准的方法。

按照这些模式,通常将网络呼叫的状态映射到一个代表呼叫状态的对象。

一个没有任何MVx模式的简单示例如下所示,其中从RXBinding观察到的调用了对API的调用,但它不仅返回了API的数据,还返回了一个状态对象,该状态对象随后可以在屏幕。

private val disposables = CompositeDisposable()

override fun onStart() {
    super.onStart()
    disposables.add(
        RxView.clicks(load_data_button)
            .flatMap { requestData() }
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(this::renderRequestState)
    )
}

override fun onStop() {
    disposables.clear()
    super.onStop()
}

private fun requestData(): Observable<RequestState> {
    return myApi.requestData()
        .toObservable()
        .subscribeOn(Schedulers.io())
        .map<RequestState>(RequestState::Success)
        .onErrorReturn(RequestState::Error)
        .startWith(RequestState.InFlight)
}

private fun renderRequestState(requestState: RequestState) {
    when (requestState) {
        RequestState.InFlight -> showProgress()
        is RequestState.Success -> showResult(requestState.result)
        is RequestState.Error -> showError(requestState.error)
    }
}

sealed class RequestState {
    object InFlight : RequestState()
    data class Success(val result: MyData) : RequestState()
    data class Error(val error: Throwable) : RequestState()
}

Hannes Dorfmann用这种方法写了很多有关MVI模式的文章。