Android中出现异常后如何重新启动/重试Kotlin协程

时间:2019-04-30 12:33:33

标签: android kotlin android-memory kotlin-coroutines

我很高兴我将长时间运行的任务切换了,这些任务不断将 UI线程结果生成为协程。与AsyncTask或Android中的常规线程相比,它提高了性能并将内存使用量减少了3倍,并且所有内存泄漏都消失了。

唯一的问题是,我不知道在出现异常某个时候 ...

之后,我应该如何重新启动长时间运行的操作。

阅读大量文章后,我觉得我根本不了解协程中的异常处理。让我知道如何实现期望的行为。

  1. 我在片段中拥有协程范围(将在不久的将来移至VM)。

    lateinit var initEngineJob: Job
    override val coroutineContext: CoroutineContext
        get() = initEngineJob + Dispatchers.Main

  1. 具有异步/等待功能的长时间运行的任务。

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
   }

我不知道应该在哪里抓鱼。我尝试将tryfer包围在deferred.await()中,但是我不能在catch块中调用相同的方法来重试长时间运行的任务。我尝试了 SupervisorJob (),但也没有成功。我仍然无法再次调用 initWorkEngineCoroutine()启动新协程 ...

最终帮助解决此问题:)

1 个答案:

答案 0 :(得分:3)

您应该将代码视为线性命令,并在代码中最合乎逻辑的地方尝试/捕获。有了这种心态,您的问题可能与协程无关,而与尝试/捕获重试有关。您可能会这样做:

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()立即引发异常并最终导致无限循环的问题,该循环可能导致意外行为和潜在的堆栈溢出。 / p>