Как мне перезапустить / повторить сопрограмму Kotlin после исключения в Android - PullRequest
1 голос
/ 30 апреля 2019

Я очень рад, что я переключил свои долгосрочные задачи, которые постоянно выдают результаты в поток пользовательского интерфейса на сопрограммы . Это улучшило производительность и уменьшило использование памяти в 3 раза, и все утечки памяти исчезли по сравнению с AsyncTask или обычными потоками в Android.

Единственная проблема остается в том, что я не знаю, как мне перезапустить мою длительную операцию после исключения в какое-то время ...

Мне кажется, я совсем не понял обработку исключений в сопрограммах после прочтения тонны статей. Дайте мне знать, как мне достичь желаемого поведения.

  1. У меня есть фрагмент сопрограммы во фрагменте (в ближайшее время я перейду к VM).

1017 *

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

& # x200B;

  1. Долгосрочное задание с асинхронным вызовом / ожиданием.

& # x200B;

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
   }

я не знаю, куда мне положить пробуй поймать. Я попытался окружить deferred.await () с помощью метода catch, но я не смог вызвать тот же метод в блоке catch , чтобы повторить долгосрочную задачу. Я пытался SupervisorJob (), но безуспешно. Я все еще не мог вызвать initWorkEngineCoroutine () снова и начать новую сопрограмму ...

Помогите окончательно решить эту проблему:)

1 Ответ

3 голосов
/ 30 апреля 2019

Вы должны относиться к своему коду как к линейному императиву и пытаться / ловить, где это имеет наиболее логичный смысл в вашем коде.При таком подходе ваш вопрос, вероятно, не столько о сопрограммах, сколько о попытках «поймать / поймать».Вы можете сделать что-то вроде этого:

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() и приводят к бесконечному циклу, который может привести к неожиданному поведению и потенциальному переполнению стека.

...