Android 如何在协程中使用超时

How to work withTimeout in Coroutine on Android

在我的应用程序中,我想使用 Coroutines 并且我编写了简单的代码来检查 withTimeout 函数!
我写了下面的代码,我想在 3sec 之后停止我的工作并向我显示 Done 消息!
但是在 3sec 停止协程后 不显示 完成消息!

我的代码:

CoroutineScope(Default).launch {
    Log.e(TAG, "Start coroutine")
    withTimeout(3000) {
        for (i in 20..50) {
            if (isActive) {
                delay(500)
                Log.e(TAG, "Show i => $i")
            }
        }
    }
    Log.e(TAG, "Done coroutine")
}

Logcat 消息:

2022-02-05 18:08:11.891 12413-12484/my.app.coroutines E/CoroutinesTag: Start coroutine
2022-02-05 18:08:12.399 12413-12484/my.app.coroutines E/CoroutinesTag: Show i => 20
2022-02-05 18:08:12.900 12413-12485/my.app.coroutines E/CoroutinesTag: Show i => 21
2022-02-05 18:08:13.404 12413-12491/my.app.coroutines E/CoroutinesTag: Show i => 22
2022-02-05 18:08:13.905 12413-12486/my.app.coroutines E/CoroutinesTag: Show i => 23
2022-02-05 18:08:14.406 12413-12491/my.app.coroutines E/CoroutinesTag: Show i => 24

为什么不显示完成(完成协程)消息?

withTimeout

的说明

Runs a given suspending block of code inside a coroutine with a specified timeout timeMillis and throws a TimeoutCancellationException if the timeout was exceeded.

TimeoutCancellationException 扩展了 CancellationException,它用于优雅地退出像 launch 这样的构建器函数。如果你不想完成你的工作,你可以使用 withTimeoutOrNull

并且来自 official docs

The TimeoutCancellationException that is thrown by withTimeout is a subclass of CancellationException. We have not seen its stack trace printed on the console before. That is because inside a cancelled coroutine CancellationException is considered to be a normal reason for coroutine completion. However, in this example we have used withTimeout right inside the main function.

Since cancellation is just an exception, all resources are closed in the usual way. You can wrap the code with timeout in a try {...} catch (e: TimeoutCancellationException) {...} block if you need to do some additional action specifically on any kind of timeout or use the withTimeoutOrNull function that is similar to withTimeout but returns null on timeout instead of throwing an exception: