我正在尝试调试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()
}
}
答案 0 :(得分:0)
我找出了原因和可能的解决方案。
让我们从原因开始。
我的代码可以这样简化:Observable#1从n个通过flatMap()
在其他线程上执行的其他Observable开始。
为简单起见,我们假设所有可观察对象都在各自的线程上执行。然后,当一个可观察对象抛出错误时,该错误将传播到所有其他可观察对象并进行处理。
问题在于此传播未同步(原因似乎是出于性能原因)。因此,tryOnError()
可以通过isDisposed()
检查,然后被处置,然后引发错误。这就解释了为什么即使使用tryOnError()
仍然会发生异常。
某些解决方案
经过一些研究和讨论,我最终提出了两个主要解决方案。
一种方法是通过onErrorReturn()
将所有错误转换为Observable中的结果。此解决方案有效,但如果您希望在遇到错误后立即停止执行,效果可能会不佳。
另一种方法是注册全局错误处理程序,而忽略这些错误。
我选择了后一种解决方案,但是我并不完全满意。我真的希望有一种注册本地错误处理程序的方法。例如。对于Observables有一种方法可以忽略在处理Observable
之后发出的错误。
好吧。