我在 Android 应用程序中遇到这样的情况:某些计算偶尔会导致 NumberFormatException。为了解决这个问题,我实现了 Try Catch 块,它有效地解决了这个问题。然而,这个解决方案导致了另一个问题——由于 UI 阻塞而导致 ANR(应用程序未响应)。经过一番调查,我了解到 Try Catch 块导致 UI 阻塞,从而导致 ANR。
我的问题是:如何在单独的后台线程上使用 Try Catch 来防止它阻塞主 UI?值得注意的是,Try Catch 块中的函数主要用于数学计算。下面是我最初实现的相关代码片段:
第一个例子:
val areaInSqMeter: Double? = try {
SphericalUtil.computeArea(geoPoints)
} catch (e: Exception) {
Log.e("MapScreen", "$e")
null
}
areaInSqMeter?.let {
// updating viemodel variables and showing data
}
第二个例子:
try {
if (isTriangleValid(
viewModel.sideA,
viewModel.sideB,
viewModel.sideC,
viewModel.sideD,
viewModel.sideE
)
) {
// calculate the area
viewModel.selectedTerritory?.let {
calculateAreaAndCadastralAndUpdateViewModel(
viewModel = viewModel,
selectedTerritoryCode = it,
context = manualMeasurementCompactScreenContext
)
focusManager.clearFocus(true)
keyboardController?.hide()
}
} else {
Toast.makeText(
manualMeasurementCompactScreenContext,
invalidValuesToast,
Toast.LENGTH_SHORT
).show()
}
} catch (e: NumberFormatException) {
Toast.makeText(
manualMeasurementContext,
manualMeasurementContext.getString(R.string.toast_error_number_format_error),
Toast.LENGTH_SHORT
).show()
}
为了不阻塞 UI,您可以使用视图模型中的协程作用域,并根据需要指定调度程序,如下所示:
viewModelScope.launch(Dispatchers.Default) {
val areaInSqMeter: Double? = try {
SphericalUtil.computeArea(geoPoints)
} catch (e: Exception) {
Log.e("MapScreen", "$e")
null
}
areaInSqMeter?.let {
// updating viemodel variables and showing data
}
}
您还可以使用 withContext() 而不是视图模型范围,如下所示:
withContext(Dispatchers.Default) {
}
假设您的计算任务与CPU密集型工作相关,您可以使用Dispacthers.Default代替IO,因为稍后它用于网络和读/写操作。您可以从此处的官方文档了解有关此主题的更多信息:https://developer.android.com/kotlin/coroutines/coroutines-adv
如果您在 UI 中想要等待结果,那么您可以将其与 LaunchedEffect 配对并提供适当的密钥以进行重组。这是我的代码中的一个示例:
LaunchedEffect(key1 = Unit, block = {
this.async(Dispatchers.Default) {
try {
extractVideoFrames(Constants.BASE_URL + clipInfo.videoURL, clipBuilderViewModel)
} catch (e: Exception) {
Timber.e("Extracting video frames failed with exception: ${e.message}")
}
}.await()
})