【问题标题】:Error CalledFromWrongThreadException when debugging rxjava调试 rxjava 时出现错误 CalledFromWrongThreadException
【发布时间】:2018-03-23 22:16:48
【问题描述】:

我有下一个代码。

private val observeRefresh = detailView.observeRefresh
            .observeOn(Schedulers.io())
            .map { _ -> detailModel.forecastCity }
            .flatMap { city ->
                detailModel.getForecast(city.id, FORECAST_COUNT)
                        .map { response -> DetailUiModel.stateSuccess(response.list, detailModel.forecastCity) }
                        .onErrorReturn { t -> DetailUiModel.stateError(t.message) }
                        .observeOn(AndroidSchedulers.mainThread())
                        .startWith(DetailUiModel.stateLoading)
            }
            .subscribe { this.handleResponse(it) }


private fun handleResponse(model: DetailUiModel) {
        detailView.setLoading(model.isLoading)
        when {
            model.success -> detailView.setForecastItems(model.data!!)
            !model.isLoading -> detailView.showError(model.error)
            model.city != null -> detailView.setMapImage(createMapUrl(model.city!!))
            else -> return
        }

    }

我想调试这一行detailView.setMapImage(createMapUrl(model.city!!))当我添加检查点应用程序抛出错误CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 如果我不添加检查点应用程序工作正常。

【问题讨论】:

  • 尝试添加 subscribeOn(...) 并向上移动 .observeOn() 以便 .map 跟随它。

标签: android kotlin rx-java2


【解决方案1】:

flatMap 可能不会从接收项目的同一线程发出,因此您必须通过在flatMap 运算符之后观察所需线程来确保在所需线程上接收事件:

detailView.observeRefresh
        .observeOn(Schedulers.io())
        .map { _ -> detailModel.forecastCity }
        .flatMap { city ->
            detailModel.getForecast(city.id, FORECAST_COUNT)
                    .map { response -> 
                        DetailUiModel.stateSuccess(response.list,
                            detailModel.forecastCity) 
                    }
                    .onErrorReturn { t -> DetailUiModel.stateError(t.message) }
        }
        .startWith(DetailUiModel.stateLoading)       // <---------------------------
        .observeOn(AndroidSchedulers.mainThread())   // <---------------------------
        .subscribe { this.handleResponse(it) }

不再需要那个内部observeOn,另外,建议你在observeOn之前移出startWith,以确保初始状态信号也在@987654327之前到达正确的线程@ 开始。

【讨论】:

  • 谢谢。现在一切正常。有趣的是,如果 Jake Warthon 不起作用,为什么要展示该方法
  • 如您所见,有时时机恰到好处。经验法则应该是将observeOn(AndroidSchedulers.mainThread()) 尽可能靠近subscribe 调用或应该在主线程上发生的处理步骤,并且当有多个这样的位置时您可能必须重复应用它。
【解决方案2】:

您应该在.subscribe { this.handleResponse(it) 之前添加observeOn(AndroidSchedulers.mainThread()) 这是完整的代码:

private val observeRefresh = detailView.observeRefresh
        .observeOn(Schedulers.io())
        .map { _ -> detailModel.forecastCity }
        .flatMap { city ->
            detailModel.getForecast(city.id, FORECAST_COUNT)
                    .map { response -> DetailUiModel.stateSuccess(response.list, detailModel.forecastCity) }
                    .onErrorReturn { t -> DetailUiModel.stateError(t.message) }
                    .observeOn(AndroidSchedulers.mainThread())
                    .startWith(DetailUiModel.stateLoading)
        }
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe { this.handleResponse(it) }

【讨论】:

  • 但是我在.onErrorReturn { t -&gt; DetailUiModel.stateError(t.message) } 之后添加了这个方法??这还不够吗?
  • 未添加调试检查点时它正在工作的有趣事情
  • 没有。该 observeOn 用于从 getForecast 函数返回的另一个 observable。但是这个 observeOn 是为你编写的主要 Observable 订阅的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-09
  • 1970-01-01
  • 2013-09-07
  • 2021-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多