android - 我应该如何在 Android 异常后重新启动/重试 Kotlin 协程

标签 android kotlin android-memory kotlin-coroutines

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

唯一的问题是,我不知道如何在异常在某个时间发生后重新启动我的长时间运行的操作......

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

  1. 我在 fragment 中有协程作用域(将在不久的将来转移到 VM)。

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

  1. 使用 async/await 的长时间运行任务。

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 block 中调用相同的方法 以重试长时间运行的任务。我尝试了 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() 立即引发异常并最终导致可能导致意外行为的无限循环的问题和潜在的计算器溢出。

关于android - 我应该如何在 Android 异常后重新启动/重试 Kotlin 协程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55921068/

相关文章:

java - Android 中线程的实现不起作用

android - 如何将android应用程序与droid mobile相匹配?

android - 从线程更改 TextView 文本

android - 为什么使用 View Binding 会改变布局?

android - 恢复时间内存优化

android - AsyncTask和运行时配置使用简洁的代码示例更改: what approaches,,Android团队认可吗?

android - google-services 和 android-gms 之间的版本冲突

java - 实现 Java 接口(interface) - Kotlin

使用 Kotlin/Firebase 的 Android Studio 代码完成 - 行为不端

android - 在 Android 中逐帧动画图像的最佳方式