Как написать Kotlin-разговорный код, чтобы повторить синхронно до тайм-аута или успеха? - PullRequest
0 голосов
/ 07 июля 2019

Прочитав документацию Kotlin, я придумал следующий код (который не работает - см. Ниже), чтобы повторить вызов функции до тех пор, пока он не вернет истину или не истечет время ожидания.
Я хочу приостановить выполнение до этого кодаблок достигает тайм-аута или успеха - он не должен выполняться асинхронно.

Log.d(TAG, "This is the last line to be logged")
runBlocking {
    Log.d(TAG, "this line is never logged")
    try {
        withTimeout(timeoutMsL) {
            while ((isActive) && (!success)) {
                success = doSomething()
            }
        } 
    }
    catch (ex: TimeoutCancellationException) {
        Log.d(TAG, "this line is never logged either")
        doSomethingElse()
    }
}

timeoutMsL - это Long с типичным значением 50 мс.Этот код вызывается из C ++ через JNI.Когда я запускаю его

  • ничего внутри блока runBlocking не запускается
  • ничего после запуска блока runBlocking
  • элемент управления возвращается к вызывающей стороне C ++
  • тамявляется исключением в JNI, но JNI не регистрирует подробности исключений Kotlin или Java.
  • в adb
  • не зарегистрировано никаких исключений, когда я попытался окружить приведенный выше фрагмент кода с помощью try /блок catch / log для перехвата исключений Kotlin, ничего не регистрируется

Я читал, что следует избегать runBlocking, но также необходимо вызвать withTimeout из существующей сопрограммы.
ЕслиЯ использую обычную сопрограмму, выполнение вызывающей функции будет продолжено до достижения тайм-аута / успеха - мне нужно предотвратить это.

Как это должно быть закодировано в Kotlin?

1 Ответ

1 голос
/ 07 июля 2019

Ваша проблема, вероятно, заключается в doSomething().Реализация сопрограммы Kotlin во многом зависит от совместного выполнения, где дочерние сопрограммы проверяют флаги, чтобы увидеть, были ли они отменены (как это сделает withTimeout()).Это будет означать, что внешние сопрограммы будут приостанавливаться до тех пор, пока они не подтвердят, что дочерние сопрограммы закончились, блокируя всю функцию.

, если doSomething никогда не приостанавливается и никогда не проверяет, активна ли она, она будет работать до завершения независимо отвнешняя ситуация.

Чтобы исправить это, есть два варианта:

  1. Сделать doSomething() функцию suspend и регулярно приостанавливать с помощью yield() или ensureActive() дляответить на отмену.
  2. Выполнить его на диспетчере, который предназначен для прерывания нормального кода блокировки, например withContext(Dispatchers.IO).
...