我很高兴我切换了长时间运行的任务,这些任务不断产生UI线程到协同程序的结果。与AsyncTask或Android中的常规线程相比,它提高了性能并减少了3倍的内存使用量,并且所有内存泄漏都消失了。
唯一的问题仍然是,我不知道如何在异常发生后重新启动我的长时间运行操作......
在阅读了大量文章之后,我觉得我根本不理解协同程序中的异常处理。让我知道如何实现理想的行为。
lateinit var initEngineJob: Job
override val coroutineContext: CoroutineContext
get() = initEngineJob + Dispatchers.Main
fun initWorkEngineCoroutine()
{
launch {
while(true) {
val deferred = async(Dispatchers.Default) {
getResultsFromEngine()
}
val result = deferred.await()
if (result != null) {
//UI thread
draw!!.showResult(result)
}
}
}
}
fun getResultsFromEngine() :Result? {
result = // some results from native c++ engine, which throws exception at some times
return result
}
我不知道我应该把try catch放在哪里。我试图用try catch包围deferred.await(),但是我无法在catch块中调用相同的方法来重试长时间运行的任务。我试过SupervisorJob(),但也没有成功。我仍然无法再次调用initWorkEngineCoroutine()并开始新的协程...
最后帮助解决这个问题:)
您应该将代码视为线性命令,并尝试/捕获代码中最具逻辑意义的代码。有了这种心态,你的问题可能不是关于协程,而是更多关于try / catch重试的问题。你可能会这样做:
fun main() {
GlobalScope.launch {
initWorkEngineCoroutine()
}
}
suspend fun initWorkEngineCoroutine() {
var failures = 0
val maxFailures = 3
while(failures <= maxFailures) {
try {
getResultsFromEngine()?.let {
draw!!.showResult(it)
}
} catch (e: Exception) {
failures++
}
}
}
// withContext is like async{}.await() except an exception occuring inside
// withContext can be caught from inside the coroutine.
// here, we are mapping getResultFromEngine() to a call to withContext and
// passing withContext the lambda which does the work
suspend fun getResultsFromEngine() :Result? = withContext(Dispatchers.Default) {
Result()
}
我已经包含了一些逻辑来防止无限循环。它可能不符合您的要求,但您可能会考虑某种事情来防止getResultsFromEngine()
立即引发异常并最终导致无限循环导致意外行为和潜在堆栈溢出的问题。