即使存在onError,RxJava平面图也会崩溃

时间:2018-10-08 10:09:37

标签: android kotlin rx-java

我正在尝试调试Android崩溃,该崩溃是在设备没有网络连接时发生的。崩溃仅有时发生(大约50%的时间),我不确定为什么。如果有人可以解释正在发生的事情或提供解决方案,我将非常感激。

我正在使用平面地图并行获取图像,并且我订阅了onError()块。尽管如此,该应用仍会崩溃。

这是代码(我用“ Crash here:”标记了崩溃的行):

library(jtools)
interact_plot(fit, pred="x2", modx="m", interval=T, int.width=0.95)
#Note on the use of this: Don't transform variables *within* your model, such as `as.factor(...)`. Apparently, the `jtools` functions cannot handel those.

堆栈跟踪:

fun downloadImages() {
    var progress = 0
    var maxProgress = 0

    downloadModel.postValue(
            Resource.inProgress(getString(R.string.downloading_offline_data)))

    disposables.add(Observable
            .create<Pair<String, File>> { emitter ->
                val files = readFileDirs()

                for (file in files) {
                  val urlList = readUrlListFrom(file)
                  maxProgress += urlList.size

                  for (url in urlList) {
                    emitter.onNext(url to file)
                  }
                }
                emitter.onComplete()
            }
            .flatMap { (url, file) ->
                downloadImage(url, file)
                        .subscribeOn(Schedulers.computation())
                        .andThen(Observable.fromCallable {
                            ++progress
                        })
            }
            .doOnDispose {
                downloadModel.postValue(Resource.idle())
            }
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe({
                Log.d(TAG, "Done downloading $it")

                if (it % 100 == 0) {
                    refreshCacheSize()
                }

                downloadModel.postValue(Resource.inProgress(
                        getString(R.string.downloading_offline_data),
                        it,
                        maxProgress
                ))
            }, { error ->
                val errorId = when (error) {
                    is SocketTimeoutException ->
                        NETWORK_TIMEOUT_ERROR
                    is InterruptedIOException -> {
                        // do nothing
                        return@subscribe
                    }
                    is UnknownHostException ->
                        NETWORK_ERROR
                    is IOException ->
                        UNKNOWN_ERROR
                    is UnsupportedServerVersionException ->
                        UNSUPPORTED_VERSION_ERROR
                    else -> {
                        UNKNOWN_ERROR
                    }
                }
                downloadModel.postValue(Resource.error(errorId))
            }, {
                refreshCacheSize()

                downloadModel.postValue(Resource.success())
            })
    )
}

private fun downloadImage(url: String, outFile: File): Completable {
    val outFileTmp = File(outFile.canonicalPath + ".tmp")
    return Completable
            .create { emitter ->
                val request = Request.Builder()
                        .url(url)
                        .build()
                try {
Crash here:          val response = Client.get().newCall(request).execute()
                    val sink: BufferedSink
                    try {
                        Log.d(TAG, "Writing to file")
                        val body = response.body()
                        if (body != null) {
                            sink = Okio.buffer(Okio.sink(outFileTmp))
                            sink.writeAll(body.source())
                            sink.close()
                        } else {
                            if (!emitter.isDisposed) {
                                emitter.onError(DownloadImageException("Body was null."))
                            }
                        }
                    } finally {
                        response.body()?.close()
                    }

                    outFileTmp.renameTo(outFile)

                    emitter.onComplete()
                } catch (e: Exception) {
                    Log.e(TAG, "Could not save splash", e)
                    emitter.tryOnError(e)
                }
            }
            .doOnDispose {
                outFileTmp.delete()
            }
            .doOnError {
                outFileTmp.delete()
            }
}

1 个答案:

答案 0 :(得分:0)

我找出了原因和可能的解决方案。

让我们从原因开始。

我的代码可以这样简化:Observable#1从n个通过flatMap()在其他线程上执行的其他Observable开始。

为简单起见,我们假设所有可观察对象都在各自的线程上执行。然后,当一个可观察对象抛出错误时,该错误将传播到所有其他可观察对象并进行处理。

问题在于此传播未同步(原因似乎是出于性能原因)。因此,tryOnError()可以通过isDisposed()检查,然后被处置,然后引发错误。这就解释了为什么即使使用tryOnError()仍然会发生异常。

某些解决方案

经过一些研究和讨论,我最终提出了两个主要解决方案。

一种方法是通过onErrorReturn()将所有错误转换为Observable中的结果。此解决方案有效,但如果您希望在遇到错误后立即停止执行,效果可能会不佳。

另一种方法是注册全局错误处理程序,而忽略这些错误。

我选择了后一种解决方案,但是我并不完全满意。我真的希望有一种注册本地错误处理程序的方法。例如。对于Observables有一种方法可以忽略在处理Observable之后发出的错误。

好吧。

相关问题