目录
asContextElement:
asCoroutineDispatcher:
js asDeferred:
asExecutor:
js asPromise:
async:
js await:
awaitAll:
awaitCancellation:
cancelAndJoin:
cancelChildren:
CancellableContinuation:
CancellationException:
CloseableCoroutineDispatcher:
CompletableDeferred:
CompletableJob:
completeWith:
CompletionHandler:
CoroutineDispatcher:
CoroutineName:
coroutineScope:
CoroutineStart:
Deferred:
delay:
Dispatchers:
ensureActive:
ensurePresent :
ExperimentalCoroutinesApi:
GlobalScope:
handleCoroutineException:
invoke:
IO:
isActive:
job:
joinAll:
launch:
MainScope:
NonCancellable:
plus:
runBlocking:
Runnable:
SupervisorJob:
supervisorScope:
suspendCancellableCoroutine:
withContext:
withTimeout :
withTimeoutOrNull :
yield:
asContextElement:
创建一个协程上下文元素(CoroutineContext.Element)
,该元素可以被添加到协程上下文中,以便在特定的协程中检索和使用
注意:上下文元素不跟踪线程局部变量的修改
示例
val myThreadLocal = ThreadLocal<String?>()
println(myThreadLocal.get()) // 打印"null"
GlobalScope.launch(Dispatchers.Default + myThreadLocal.asContextElement(value = "foo")) {
println(myThreadLocal.get()) // 打印“foo”
withContext(Dispatchers.Main) {
println(myThreadLocal.get()) // UI线程上 打印“foo”
}
}
println(myThreadLocal.get())// 打印"null"
asCoroutineDispatcher:
将常规的java.util.concurrent.Executor
转换为 Kotlin 协程中的 CoroutineDispatcher,
CoroutineDispatcher
是协程中用于调度协程执行的抽象,它决定了协程运行在哪个线程或线程池中。
示例
// 创建一个固定大小的线程池
val executor = Executors.newFixedThreadPool(2)
// 将线程池转换为 CoroutineDispatcher
val dispatcher: CoroutineDispatcher = executor.asCoroutineDispatcher()
// 在指定的调度器上启动协程
runBlocking(dispatcher) {
launch {
println("Task 1 is running on ${Thread.currentThread().name}")
}
launch {
println("Task 2 is running on ${Thread.currentThread().name}")
}
}
// 关闭线程池
executor.shutdown()
js asDeferred:
将JavaScript中的Promise
对象转换为Deferred
类型
示例
runBlocking {
val deferredResult = async {
// 模拟一个异步操作
delay(1000)
// Async operation completed
}
// 将 Deferred 对象转换为 Deferred 类型
val convertedDeferred: Deferred<String> = deferredResult.asDeferred()
// 等待异步操作完成
val result = convertedDeferred.await()
println(result)
}
asExecutor:
将CoroutineDispatcher
转换为Executor
接口。这对于与使用Java的一些库和API集成时很有用,因为它们可能期望一个Executor
而不是CoroutineDispatcher
示例
val dispatcher: CoroutineDispatcher = Dispatchers.Default
// 使用asExecutor将CoroutineDispatcher转换为Executor
val executor: Executor = dispatcher.asExecutor()
// 然后可以将其用于与期望Executor的Java库或API进行交互
val runnable = Runnable {
println("Running on executor")
}
executor.execute(runnable)
js asPromise:
Deferred
对象转换为JavaScript中的Promise
对象。主要用于与基于Promise的异步编程框架
示例
suspend fun performAsyncTask(): String {
// Simulate an asynchronous task
kotlinx.coroutines.delay(1000)
return "Task completed"
}
fun main() {
// Start an asynchronous task using async
val asyncTask = lifecycleScope.async {
performAsyncTask()
}
// Convert the async task to a Promise
val promise: Promise<String> = asyncTask.asPromise()
// Handle the Promise in JavaScript-like style
promise.then(
onFulfilled = { result ->
console.log("Promise resolved: $result")
},
onRejected = { reason ->
console.error("Promise rejected: $reason")
}
)
// In a real application, you might want to wait for the Promise to complete
// before exiting the program. This is just a simple example.
}
async:
Kotlin 协程库提供的一个构建器,用于在协程中执行异步任务。它与 launch
不同,async
返回一个 Deferred
对象,该对象包含异步任务的结果 这个就不写示例了 上面示例有
js await:
毫无阻碍地等待承诺的完成。
awaitAll:
并发执行多个异步任务并等待它们全部完成。你可以使用async
启动这些任务,然后使用awaitAll
等待它们的完成。
示例
fun main() = runBlocking {
val deferred1 = async { fetchDataFromNetwork1() }
val deferred2 = async { fetchDataFromNetwork2() }
// 等待两个异步任务完成
val result = try {
awaitAll(deferred1, deferred2)
} catch (e: Exception) {
// 处理异常
}
// 得到结果
println(result)
}
private suspend fun fetchDataFromNetwork1(): String {
// 模拟从网络获取数据的异步操作
delay(1000)
return "Data from Network 1"
}
private suspend fun fetchDataFromNetwork2(): String {
// 模拟从网络获取数据的异步操作
delay(1500)
return "Data from Network 2"
}
awaitCancellation:
在协程中挂起,直到协程被取消。当协程被取消时,该函数将抛出CancellationException
,而不是返回Nothing。
示例
fun main() = runBlocking {
val job = launch {
try {
// 执行一些耗时任务
repeat(1000) { i ->
println("Task is running: $i")
delay(500)
}
} finally {
println("Task is cancelled")
}
}
// 模拟一段时间后取消协程
delay(2500)
job.cancelAndJoin()
// 这里的协程将一直挂起,直到它被取消
awaitCancellation()
}
Task is running: 0
Task is running: 1
Task is running: 2
Task is running: 3
Task is running: 4
Task is cancelled
cancel:
取消操作
示例
fun main() = runBlocking {
val job = CoroutineScope(Dispatchers.Default).launch {
try {
// 在这里执行一些异步操作,例如网络请求或耗时计算
withContext(Dispatchers.IO) {
// 模拟一个耗时操作
delay(1000)
}
// 在异步操作完成后执行一些操作
println("Task completed successfully")
} catch (e: CancellationException) {
// 在取消时的处理
println("Task was cancelled")
}
}
//取消
job.cancel()
delay(5000)//防止跑完 还没打印Task was cancelled就停止了
}
Task was cancelled
cancelAndJoin:
取消任务并挂起调用协程,直到取消的任务完成。示例
fun main() = runBlocking {
val job = CoroutineScope(Dispatchers.IO).launch {
try {
// 模拟一个耗时的操作
repeat(100) { index ->
println("Coroutine is running: $index")
delay(100)
}
} finally {
// 协程完成或取消时执行的清理工作
println("Coroutine cleanup")
}
}
// 取消并等待协程完成
job.cancelAndJoin()
}
cancelChildren:
取消指定协程的所有子协程 示例
fun main() = runBlocking {
startAsyncTasks()
delay(1500)
stopAsyncTasks()
delay(10000)
}
private var parentJob: Job? = null
fun startAsyncTasks() {
// 创建一个父协程作业
parentJob = CoroutineScope(Dispatchers.IO).launch {
try {
// 启动多个子协程来执行异步任务
val job1 = async { fetchDataFromNetwork1() }
val job2 = async { fetchDataFromNetwork2() }
// 等待所有子协程完成
val awaitAll = awaitAll(job1, job2)
// 所有任务完成后的操作
// ...
println(awaitAll)
} catch (e: CancellationException) {
// 当父协程被取消时,会进入此块
// 可以在这里处理取消时的清理工作
// ...
println("Task was cancelled")
}
}
}
fun stopAsyncTasks() {
// 取消父协程的所有子协程
parentJob?.cancelChildren()
}
private suspend fun fetchDataFromNetwork1(): String {
// 模拟从网络获取数据的异步操作
delay(1000)
return "Data from Network 1"
}
private suspend fun fetchDataFromNetwork2(): String {
// 模拟从网络获取数据的异步操作
delay(3500)
return "Data from Network 2"
}
Task was cancelled
CancellableContinuation:
提供对协程取消的更细粒度控制,在协程执行期间能够检查和响应取消操作。
State | isActive | isCompleted | isCancelled |
---|---|---|---|
Active (initial state) | true |
false |
false |
Resumed (final completed state) | false |
true |
false |
Canceled (final completed state) | false |
true |
true |
+-----------+ resume +---------+
| Active | ----------> | Resumed |
+-----------+ +---------+
|
| cancel
V
+-----------+
| Cancelled |
+-----------+
示例
fun main() = runBlocking{
try {
val result = withTimeout(5000) {
// 模拟一个需要时间较长的操作
performLongRunningOperation()
}
// 操作成功完成
println("Operation result: $result")
} catch (e: TimeoutCancellationException) {
// 操作超时
println("Operation timed out")
}
}
// 模拟一个需要时间较长的操作
private suspend fun performLongRunningOperation(): String = suspendCancellableCoroutine { continuation ->
val job = GlobalScope.launch(Dispatchers.IO) {
// 模拟一个长时间运行的任务
delay(10000)
println("任务完成")
// 如果协程没有被取消,就恢复 continuation
if (continuation.isActive) {
println("isActive == ture")
continuation.resume("Operation completed successfully"){
println("resume ${it.message}")
}
}
}
// 注册一个取消回调,以便在协程被取消时取消这个任务
continuation.invokeOnCancellation {
println("invokeOnCancellation ${it?.message}")
job.cancel()
}
}
CancellationException:
取消异常
CloseableCoroutineDispatcher:
继承至CoroutineDispatcher额外提供了一个关闭它的方法,导致拒绝任何新任务,并清除与当前调度程序关联的所有底层资源
示例
class CustomDispatcher : CloseableCoroutineDispatcher() {
// 自定义调度逻辑的实现
override fun dispatch(context: CoroutineContext, block: Runnable) {
// 在这里实现自定义的调度逻辑
executor.submit {
block.run()
}
}
//原子操作
private val closed = AtomicBoolean(false)
override val executor: ExecutorService
get() = Executors.newSingleThreadExecutor()
override fun close() {
if (closed.compareAndSet(false, true)) {
// 在这里执行关闭资源的逻辑
// 这个示例中简单地关闭线程池
executor.shutdown()
println("Closing resources...")
}
}
}
fun main() = runBlocking {
// 示例中使用自定义调度程序
val customDispatcher = CustomDispatcher()
customDispatcher.use { customDispatcher ->
// 使用 withContext 指定自定义调度器
withContext(customDispatcher) {
// 在自定义调度器上执行异步任务
println("Running on custom dispatcher - Thread: ${Thread.currentThread().name}")
}
}
}
CompletableDeferred:
CompletableDeferred 是 Kotlin 协程库中的一个类,用于表示异步操作的结果。它是 Deferred 的一个特殊实现,专注于没有返回值的异步操作(Completable Deferred,无返回值)。CompletableDeferred 有两个主要的函数:complete 和 await。
- complete: 用于完成这个 CompletableDeferred,表示异步操作已经完成。
- await: 用于等待异步操作完成,它是一个挂起函数,可以在协程中使用。
class MyAsyncTask {
// 使用 CompletableDeferred 作为异步任务的结果
private val completableDeferred = CompletableDeferred<Unit>()
fun doAsyncTask() {
// 在后台启动一个协程执行异步任务
GlobalScope.launch {
// 模拟异步任务的耗时操作
simulateAsyncOperation()
// 异步任务完成时调用 complete
completableDeferred.complete(Unit)
}
}
suspend fun getResult() {
// 等待异步任务完成
completableDeferred.await()
// 这里可以在主线程中处理异步任务完成后的逻辑
}
private suspend fun simulateAsyncOperation() {
// 模拟异步操作的耗时
println("In the consumption of time.")
delay(3000)
println("Time-consuming completion.")
}
}
fun main() = runBlocking {
val myAsyncTask = MyAsyncTask()
// 启动异步任务
myAsyncTask.doAsyncTask()
// 等待异步任务完成
myAsyncTask.getResult()
println("Async task completed.")
}
In the consumption of time.
Time-consuming completion.
Async task completed.
CompletableJob:
CompletableJob 在 Job 的基础上添加了一些额外的功能,使得它更适合一些特定的使用场景。CompletableJob 允许你手动完成(complete 一个任务。在协程中,当你使用 launch、async 等构建器创建协程时,它们会返回一个 Job 对象。这个 Job 对象就是协程的引用,你可以使用这个引用来控制协程的生命周期。
// 创建一个 CompletableJob
val completableJob = Job()
// 创建一个 CoroutineScope,并关联上面的 CompletableJob
val coroutineScope = CoroutineScope(Dispatchers.Default + completableJob)
// 启动一个协程
val job = coroutineScope.launch {
// 协程的逻辑
delay(1000) // 模拟一些工作
//任务完成时手动完成 job
completableJob.complete()
// 任务完成后,可以执行一些操作
println("Coroutine completed")
}
// 可以添加监听器来处理任务完成的事件
completableJob.invokeOnCompletion {
println("Job completed")
// 可以在这里执行一些额外的操作
}
// 在主线程中等待协程完成
runBlocking {
//手动完成 job
job.join()
}
Coroutine completed
Job completed
completeWith:
这个方法的作用是将将给定的 Result
对象的结果结果(成功或失败)传递给 CompletableDeferred。completeWith 返回一个布尔值,表示操作是否成功。如果 CompletableDeferred 已经被完成过,那么这个方法将返回 false。
runBlocking{
val completableDeferred = CompletableDeferred<String>()
// 在后台线程中模拟异步操作,并将结果传递给 CompletableDeferred
GlobalScope.launch(Dispatchers.IO) {
try {
// 模拟异步操作成功,并将结果传递给 CompletableDeferred
val result = Result.success("Operation completed successfully")
completableDeferred.completeWith(result)
} catch (e: Exception) {
// 模拟异步操作失败,并将异常传递给 CompletableDeferred
val result = Result.failure<String>(e)
completableDeferred.completeWith(result)
}
}
// 等待异步操作的结果
val result = completableDeferred.await()
// 打印结果
println(result)
}
CompletionHandler:
对于 Job.invokeOnCompletion 和 CancellableContinuation.invokeOnCancellation 的处理程序
安装的处理程序不应抛出任何异常。如果出现异常,它们将被捕获,封装成 CompletionHandlerException,并重新抛出,可能导致与无关的代码崩溃。传递给处理程序的 cause 的含义:
- 当任务正常完成时,cause 为 null。
- 当任务被正常取消时,cause 为 CancellationException。不应将其视为错误。特别是不应将其报告到错误日志中。
- 否则,任务失败。
注意:这种类型是支持父子层次结构并允许实现等待 Job 状态的挂起函数的内部机制的一部分。此类型不应在一般应用程序代码中使用。CompletionHandler 的实现必须快速且无锁。
val job = GlobalScope.launch {
// 协程的代码
delay(1000)
throw RuntimeException("Async task failed")
println("Coroutine completed")
}
// 设置协程完成时的处理程序
job.invokeOnCompletion { cause ->
when (cause) {
null -> {
println("Job completed successfully")
}
is CancellationException -> {
println("Job was cancelled")
}
else -> {
println("Job failed with exception: $cause")
}
}
}
// 等待协程完成
runBlocking {
job.join()
}
Exception in thread "DefaultDispatcher-worker-1" java.lang.RuntimeException: Exception while trying to handle coroutine exception
at kotlinx.coroutines.CoroutineExceptionHandlerKt.handlerException(CoroutineExceptionHandler.kt:38)
at kotlinx.coroutines.CoroutineExceptionHandlerImplKt.handleCoroutineExceptionImpl(CoroutineExceptionHandlerImpl.kt:52)
at kotlinx.coroutines.CoroutineExceptionHandlerKt.handleCoroutineException(CoroutineExceptionHandler.kt:33)
at kotlinx.coroutines.StandaloneCoroutine.handleJobException(Builders.common.kt:196)
at kotlinx.coroutines.JobSupport.finalizeFinishingState(JobSupport.kt:229)
at kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath(JobSupport.kt:906)
at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:863)
at kotlinx.coroutines.JobSupport.makeCompletingOnce$kotlinx_coroutines_core(JobSupport.kt:828)
at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:100)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
Suppressed: java.lang.RuntimeException: Async task failed
at com.yang.myapplication.MainActivityKt$main$job$1.invokeSuspend(MainActivity.kt:65)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
... 5 more
Caused by: java.lang.NoClassDefFoundError: android/os/Build$VERSION
at kotlinx.coroutines.android.AndroidExceptionPreHandler.handleException(AndroidExceptionPreHandler.kt:47)
at kotlinx.coroutines.CoroutineExceptionHandlerImplKt.handleCoroutineExceptionImpl(CoroutineExceptionHandlerImpl.kt:48)
... 13 more
Caused by: java.lang.ClassNotFoundException: android.os.Build$VERSION
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
... 15 more
Exception in thread "DefaultDispatcher-worker-1" java.lang.RuntimeException: Async task failed
at com.yang.myapplication.MainActivityKt$main$job$1.invokeSuspend(MainActivity.kt:65)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@6cb2c53e, Dispatchers.Default]
Job failed with exception: java.lang.RuntimeException: Async task failed
CoroutineDispatcher:
所有协程调度程序实现扩展的基类
以下是 CoroutineDispatcher 的一些标准实现,它们由 kotlinx.coroutines 提供,并作为 Dispatchers 对象的属性:
- Dispatchers.Default:用于所有标准构建器,如果它们的上下文中没有指定调度器或任何其他 ContinuationInterceptor。使用一个共享的后台线程池,适用于消耗 CPU 资源的计算密集型协程。
- Dispatchers.IO:使用一个共享的线程池,在需要时创建线程,设计用于处理 IO 密集型的阻塞操作(如文件 I/O 和阻塞的套接字 I/O)。
- Dispatchers.Unconfined:在当前调用帧中启动协程执行,直到第一个挂起点,在那时协程构建器函数返回。协程将在稍后由相应的挂起函数使用的任何线程中恢复,而不限制在特定的线程或线程池中。Unconfined 调度器通常不应该在代码中使用。
- 私有线程池可以使用 newSingleThreadContext 和 newFixedThreadPoolContext 创建。
- 任意的 java.util.concurrent.Executor 可以使用 asCoroutineDispatcher 扩展函数转换为调度器。
在 Android 中,你可以使用这些调度器来指定协程的执行上下文,以便它们在适当的线程或线程池中运行,从而更好地管理并发和异步操作。
CoroutineName:
提供了一种在协程上下文中携带协程名字信息的方式,使得在调试和日志输出时能够更容易地追踪协程的执行。
// 在主线程启动一个协程
runBlocking {
// 在 IO 线程执行异步操作
val result = withContext(Dispatchers.IO) {
// 协程名字为 "IOOperation"
val operationName = CoroutineName("IOOperation")
// 在 IO 线程中携带协程名字
val result = withContext(operationName + Dispatchers.IO) {
// 执行一些耗时的 IO 操作
"Result from IO operation"
}
// 打印协程名字
println("Coroutine name: ${operationName.name}")
result
}
// 打印异步操作的结果
println("Result on Main thread: $result")
}
Coroutine name: IOOperation
Result on Main thread: Result from IO operation
coroutineScope:
另一种创建 CoroutineScope 并使用此范围调用挂起块的方式。它设计用于并发分解工作。提供的范围从外部范围继承其 coroutineContext,但覆盖上下文的 Job。如果此范围内的任何子协程失败,则此范围失败,其余的所有子协程都会被取消。
suspend fun showSomeData() = coroutineScope {
val data = async(Dispatchers.IO) {
// ... 为主线程加载一些 UI 数据 ...
}
withContext(Dispatchers.Main) {
doSomeWork()
val result = data.await()
display(result)
}
}
CoroutineStart:
CoroutineStart 是 Kotlin 协程库中用于协程启动的枚举类,它定义了在协程构建器(如 launch、async 等)中用作 start 参数的选项。以下是这些选项的简要概述:
- DEFAULT:默认选项,会根据协程的上下文立即安排协程执行。
- LAZY:懒启动选项,只有在需要的时候才启动协程。
- ATOMIC:原子启动选项,在不可取消的方式下,根据协程的上下文立即安排协程执行。
- UNDISPATCHED:无调度启动选项,会在当前线程中立即执行协程,直到遇到第一个挂起点。
runBlocking { // 示例:使用 DEFAULT 启动协程 val job = GlobalScope.launch(start = CoroutineStart.DEFAULT) { println("Coroutine started") delay(1000) println("Coroutine completed") } job.join() // 示例:使用 LAZY 启动协程 val lazyJob = GlobalScope.launch(start = CoroutineStart.LAZY) { println("Lazy Coroutine started") delay(1000) println("Lazy Coroutine completed") } lazyJob.start() // 手动启动 lazyJob.join() // 示例:使用 ATOMIC 启动协程 val atomicJob = GlobalScope.launch(start = CoroutineStart.ATOMIC) { println("Atomic Coroutine started") delay(1000) println("Atomic Coroutine completed") } atomicJob.join() // 示例:使用 UNDISPATCHED 启动协程 val undispatchedJob = GlobalScope.launch(start = CoroutineStart.UNDISPATCHED) { println("Undispatched Coroutine started") delay(1000) println("Undispatched Coroutine completed") } undispatchedJob.join() }
Deferred:
一种非阻塞的可取消 future。它是 Job 的子类,表示具有结果的任务。
fun main() = runBlocking {
// 创建一个 Deferred 对象
val deferred: Deferred<Int> = async {
delay(1000) // 模拟耗时操作
42 // 返回结果
}
// 在不阻塞线程的情况下等待 Deferred 完成,并获取结果
val result: Int = deferred.await()
println("Result: $result")
}
Result: 42
delay:
提供的一个挂起函数,用于在协程中进行延迟操作,而不会阻塞线程。它有两个重载形式
- suspend fun delay(timeMillis: Long)
- suspend fun delay(duration: Duration)
这两个函数都能够将协程挂起一段时间,然后再继续执行。它们的作用是为了模拟暂停,而不是直接阻塞线程。
runBlocking {
println("Start")
delay(Duration.ofSeconds(1)) // 挂起协程 1 秒
println("After delay")
}
Dispatchers:
参考CoroutineDispatcher
ensureActive:
确保当前协程仍然保持活跃状态,如果协程或作业不再活跃,它会抛出 CancellationException 异常。该函数提供了更精确的异常,因此你可以在协程内捕获 CancellationException,以便更好地处理取消的情况。
runBlocking {
launch {
try {
// 模拟耗时操作
repeat(1000) {
// 确保协程仍处于活动状态
ensureActive()
// 一些工作
println("Working $it")
delay(100)
}
} catch (e: CancellationException) {
// 在协程被取消时执行的代码
println("Coroutine cancelled: ${e.message}")
}
}
// 等待一段时间,然后取消协程
delay(500)
coroutineContext.cancelChildren()
}
Working 0
Working 1
Working 2
Working 3
Working 4
Coroutine cancelled: StandaloneCoroutine was cancelled
ensurePresent
:
用于检查当前协程上下文中是否包含指定的 ThreadLocal 实例。如果该 ThreadLocal 不存在于协程上下文中,ensurePresent 会抛出 IllegalStateException。这有助于避免在协程中使用过时的或无效的 ThreadLocal 值,从而提高代码的健壮性
ExperimentalCoroutinesApi:
标记仍处于实验的coroutines API中,这意味着相应声明的设计存在公开的问题,这些问题可能会(也可能不会)导致它们在将来发生变化。粗略地说,这些声明有可能在不久的将来被弃用,或者它们行为的语义可能会以某种方式改变,这可能会破坏一些代码。
GlobalScope:
全局作用域用于启动顶级协程,这些协程在整个应用程序生命周期内运行,不会过早取消。请在有限的情况下合理安全地使用。
@OptIn(DelicateCoroutinesApi::class)
GlobalScope.launch {
while (true) {
delay(1000)
println("GlobalScope run once")
}
}
handleCoroutineException:
介绍:为协程构建器的实现提供一个辅助函数,是为了防止异常丢失而设计的,是一种最后的手段。用于处理那些在协程中未捕获且不能通过正常方式(比如使用 try-catch)处理的异常。
runBlocking {
val exceptionHandler = CoroutineExceptionHandler { _, exception ->
println("Caught an exception: $exception")
}
// 在这里,我们故意抛出一个异常,但由于有异常处理器,异常将被捕获。
val job = launch(exceptionHandler) {
throw RuntimeException("Intentional exception")
}
job.join() // 等待作业完成
}
invoke:
扩展函数,其作用是在指定的 CoroutineDispatcher 上调用给定的挂起块,并等待其完成,然后返回结果。
runBlocking {
// 在 IO 线程上执行 fetchDataFromNetwork
val networkData = Dispatchers.IO.invoke {
fetchDataFromNetwork()
}
// 在默认的调度器上执行 fetchDataFromDisk
val diskData = Dispatchers.Default.invoke {
fetchDataFromDisk()
}
//2000+3000 后打印
println("Network Data: $networkData")
println("Disk Data: $diskData")
}
Network Data: Data from network
Disk Data: Data from disk
IO:
Dispatchers.IO 是一个专门设计用于将阻塞 I/O 任务卸载到共享线程池的协程调度器
- 默认情况下,IO 线程池大小为 64。
- Dispatchers.IO 具有独特的弹性特性。使用 CoroutineDispatcher.limitedParallelism 可以获取不受 Dispatchers.IO 并行性限制
isActive:
介绍:检查协程是否处于活动状态的属性
runBlocking {
val job = launch {
repeat(1000) { i ->
// 检查协程是否仍处于活动状态
if (!isActive) {
println("Cancelling due to isActive = false")
return@launch
}
println("I'm sleeping $i ...")
delay(500L)
}
}
delay(1300L) // 等待一段时间
// 取消协程
println("main: Cancelling the job!")
job.cancelAndJoin()
println("main: Quitting")
//coroutineContext.isActive表达式是的快捷方式get(Job)?.isActive ?: true
//while (coroutineContext.isActive) {
// do some computation
//}
}
I'm sleeping 0 ...
I'm sleeping 1 ...
I'm sleeping 2 ...
main: Cancelling the job!
main: Quitting
job:
是 Kotlin 协程中的一个关键概念,用于表示一个可以取消的、带有生命周期的任务
- Cancellation(取消): Job 可以被取消,用于中断任务的执行。取消一个 Job 会导致它的所有子 Job 也被递归地取消。
- Hierarchy(层次结构): Job 可以组成父子关系的层次结构,其中父 Job 的取消会立即取消所有子 Job。
- 状态管理: Job 有多个状态,包括 New、Active、Completing、Cancelling、Cancelled 和 Completed。这些状态反映了 Job 的生命周期。
State isActive isCompleted isCancelled New (optional initial state) false
false
false
Active (default initial state) true
false
false
Completing (transient state) true
false
false
Cancelling (transient state) false
false
true
Cancelled (final state) false
true
true
Completed (final state) false
true
false
- Exception Handling(异常处理): 通过 Job,你可以处理任务执行过程中的异常,区分正常取消和异常取消。
- Concurrency and synchronization(并发和同步): Job 及其派生接口的所有函数都是线程安全的,可以从并发的协程中安全地调用,无需外部同步。
val job: Job = GlobalScope.launch {
// 协程的执行逻辑
delay(1000)
println("Coroutine completed")
}
// 在这里,我们可以对协程进行取消
// job.cancel()
// 等待协程完成
runBlocking {
job.join()
}
val job: CompletableJob = Job()
GlobalScope.launch(job) {
// 协程的执行逻辑
delay(1000)
println("Coroutine completed")
}
// 在这里,我们可以对协程进行取消
// job.complete()
// 等待协程完成
runBlocking {
job.join()
}
joinAll:
用于挂起当前协程,直到传递的所有 Job 完成为止。这是一个方便的方法,可以等待多个协程的完成,而不必在代码中使用 job.join() 多次。
- 挂起当前协程直到所有给定的 Job 完成
runBlocking { val job1 = launch { /* 协程1的逻辑 */ } val job2 = launch { /* 协程2的逻辑 */ } val job3 = launch { /* 协程3的逻辑 */ } joinAll(job1, job2, job3) }
- 挂起当前协程直到集合中的所有 Job 完成
runBlocking { val jobs = listOf( launch { /* 协程1的逻辑 */ }, launch { /* 协程2的逻辑 */ }, launch { /* 协程3的逻辑 */ } ) jobs.joinAll() }
launch:
启动协程的一个函数
MainScope:
介绍:为UI组件创建主协同作用域我一般理解为Android的Activity协程作用域
class MyAndroidActivity {
private val scope = MainScope()
override fun onDestroy() {
super.onDestroy()
scope.cancel()
}
}
NonCancellable:
一个特殊的 Job 对象,用于创建一个非可取消的协程。它是为了在某些代码块中防止被取消而设计的,通常与 withContext 函数一起使用。
注意:NonCancellable 并不是为了用在 launch、async 等协程构建器中的。如果你使用
launch(NonCancellable) { ... }
不仅新启动的任务不会在父任务被取消时取消,整个父子关系也会被切断。父任务将不等待子任务完成,也不会在子任务出现崩溃时被取消。
fun main() = runBlocking {
val coroutineScope = CoroutineScope(Dispatchers.IO).launch {
withContext(NonCancellable+Dispatchers.Default) {
repeat(10){
delay(1000)
println("NonCancellable print $it")
}
}
}
coroutineScope.cancel()
//防止整个线程退出 测试用
delay(19000)
}
NonCancellable print 0
NonCancellable print 1
NonCancellable print 2
NonCancellable print 3
NonCancellable print 4
NonCancellable print 5
NonCancellable print 6
NonCancellable print 7
NonCancellable print 8
NonCancellable print 9
plus:
扩展函数,它的作用是将指定的协程上下文(CoroutineContext)添加到当前协程作用域 (CoroutineScope) 中,并覆盖当前作用域上下文中的相应键。这是为了方便地创建一个新的协程作用域,其中包含了当前作用域的上下文以及额外添加的上下文。
比如上面“NonCancellable+Dispatchers.Default”
runBlocking:
运行一个新的协程阻碍当前线程,直到它完成。这个函数不应该在协程中使用。它旨在将常规的阻塞代码与以挂起方式编写的库连接起来,以便在main函数和测试中。
Runnable:
用于表示一个可以在异步环境中执行的任务。在 kotlinx.coroutines 中,这个接口被扩展,以支持协程调度
class MyRunnable : Runnable {
override fun run() {
println("Hello from Runnable!")
}
}
// 在协程中执行
fun main() = runBlocking {
val runnable = MyRunnable()
val dispatcher: CoroutineDispatcher = Dispatchers.Default
dispatcher.dispatch(coroutineContext,runnable)
}
Hello from Runnable!
SupervisorJob:
一种特殊类型的 Job,它用于创建协程的层级结构,其中子协程的失败不会影响其它子协程。这允许在协程的层级结构中灵活地处理失败。supervisor可以实施自定义策略来处理其子项的失败。
注意:不管如何父线程要是崩了子协程一样也是活不了的
- launch创建的子协程,可以通过上下文中的CoroutineExceptionHandler来处理。(实施自定义策略)
- async创建的子协程,可以通过Deferred.await对结果延迟值进行处理(也需要实施自定义策略不然结果返回一样崩)
runBlocking{ val supervisor = SupervisorJob(coroutineContext.job) // 创建一个 SupervisorJob 作为子协程 val coroutineScope = CoroutineScope(supervisor) // 使用 supervisor 作为协程的 Job coroutineScope.launch { // 执行一些操作 delay(1000) println("Hello from SupervisorJob launch") throw RuntimeException("Child Coroutine 1 failed!") } coroutineScope.async { // 执行一些异步操作 delay(1500) println("Hello from SupervisorJob async") } CoroutineScope(supervisor).launch{ // 执行一些异步操作 delay(100) println("Hello from launch1") //throw RuntimeException("lead to Parent Coroutine 1 failed!") delay(2000) println("Hello from launch2") } } //这玩意我放fun main 跑的时候居然一直在运行很奇怪 Hello from launch1 Hello from SupervisorJob launch Exception in thread "DefaultDispatcher-worker-2" java.lang.RuntimeException: Exception while trying to handle coroutine exception at kotlinx.coroutines.CoroutineExceptionHandlerKt.handlerException(CoroutineExceptionHandler.kt:38) at kotlinx.coroutines.CoroutineExceptionHandlerImplKt.handleCoroutineExceptionImpl(CoroutineExceptionHandlerImpl.kt:52) at kotlinx.coroutines.CoroutineExceptionHandlerKt.handleCoroutineException(CoroutineExceptionHandler.kt:33) at kotlinx.coroutines.StandaloneCoroutine.handleJobException(Builders.common.kt:196) at kotlinx.coroutines.JobSupport.finalizeFinishingState(JobSupport.kt:229) at kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath(JobSupport.kt:906) at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:863) at kotlinx.coroutines.JobSupport.makeCompletingOnce$kotlinx_coroutines_core(JobSupport.kt:828) at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:100) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106) at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664) Suppressed: java.lang.RuntimeException: Child Coroutine 1 failed! at com.yang.myapplication.MainActivityKt$main$1$1.invokeSuspend(MainActivity.kt:82) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) ... 5 more Caused by: java.lang.NoClassDefFoundError: android/os/Build$VERSION at kotlinx.coroutines.android.AndroidExceptionPreHandler.handleException(AndroidExceptionPreHandler.kt:47) at kotlinx.coroutines.CoroutineExceptionHandlerImplKt.handleCoroutineExceptionImpl(CoroutineExceptionHandlerImpl.kt:48) ... 13 more Caused by: java.lang.ClassNotFoundException: android.os.Build$VERSION at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520) ... 15 more Exception in thread "DefaultDispatcher-worker-2" java.lang.RuntimeException: Child Coroutine 1 failed! at com.yang.myapplication.MainActivityKt$main$1$1.invokeSuspend(MainActivity.kt:82) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106) at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664) Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@3ca7b389, Dispatchers.Default] Hello from SupervisorJob async Hello from launch2
supervisorScope:
快捷的创建上述SupervisorJob
runBlocking{
supervisorScope {
launch {
delay(1000)
println("Hello from SupervisorJob launch")
throw RuntimeException("Child Coroutine 1 failed!")
}
async {
delay(1500)
println("Hello from SupervisorJob async")
}
launch {
delay(2000)
println("Hello from SupervisorJob launch")
}
}
launch{
delay(2500)
println("Hello from launch2")
coroutineContext.job.cancel()
}
}
Hello from SupervisorJob launch
Exception in thread "main" java.lang.RuntimeException: Exception while trying to handle coroutine exception
at kotlinx.coroutines.CoroutineExceptionHandlerKt.handlerException(CoroutineExceptionHandler.kt:38)
at kotlinx.coroutines.CoroutineExceptionHandlerImplKt.handleCoroutineExceptionImpl(CoroutineExceptionHandlerImpl.kt:52)
at kotlinx.coroutines.CoroutineExceptionHandlerKt.handleCoroutineException(CoroutineExceptionHandler.kt:33)
at kotlinx.coroutines.StandaloneCoroutine.handleJobException(Builders.common.kt:196)
at kotlinx.coroutines.JobSupport.finalizeFinishingState(JobSupport.kt:229)
at kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath(JobSupport.kt:906)
at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:863)
at kotlinx.coroutines.JobSupport.makeCompletingOnce$kotlinx_coroutines_core(JobSupport.kt:828)
at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:100)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:234)
at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
at kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched(CancellableContinuationImpl.kt:518)
at kotlinx.coroutines.EventLoopImplBase$DelayedResumeTask.run(EventLoop.common.kt:500)
at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:284)
at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
at com.yang.myapplication.MainActivityKt.main(MainActivity.kt:74)
at com.yang.myapplication.MainActivityKt.main(MainActivity.kt)
Suppressed: java.lang.RuntimeException: Child Coroutine 1 failed!
at com.yang.myapplication.MainActivityKt$main$1$1$1.invokeSuspend(MainActivity.kt:79)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
... 15 more
Caused by: java.lang.NoClassDefFoundError: android/os/Build$VERSION
at kotlinx.coroutines.android.AndroidExceptionPreHandler.handleException(AndroidExceptionPreHandler.kt:47)
at kotlinx.coroutines.CoroutineExceptionHandlerImplKt.handleCoroutineExceptionImpl(CoroutineExceptionHandlerImpl.kt:48)
... 23 more
Caused by: java.lang.ClassNotFoundException: android.os.Build$VERSION
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
... 25 more
Exception in thread "main" java.lang.RuntimeException: Child Coroutine 1 failed!
at com.yang.myapplication.MainActivityKt$main$1$1$1.invokeSuspend(MainActivity.kt:79)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:234)
at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
at kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched(CancellableContinuationImpl.kt:518)
at kotlinx.coroutines.EventLoopImplBase$DelayedResumeTask.run(EventLoop.common.kt:500)
at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:284)
at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
at com.yang.myapplication.MainActivityKt.main(MainActivity.kt:74)
at com.yang.myapplication.MainActivityKt.main(MainActivity.kt)
Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@58701e8c, BlockingEventLoop@951461a]
Hello from SupervisorJob async
Hello from SupervisorJob launch
Hello from launch2
suspendCancellableCoroutine:
一个用于支持协程挂起的函数。它的主要作用是允许你在协程中等待一个单次回调的结果,并将结果返回给调用方。它提供了对取消的支持,确保在协程取消时及时清理资源。
val mockApi = MockApi()
suspend fun awaitCallback() = suspendCancellableCoroutine { continuation ->
val callback = object : Callback {
override fun onCompleted(value: String) {
println("onCompleted $value")
// 用回调提供的值恢复协程
continuation.resume(value)
}
override fun onApiError(cause: Throwable) {
// 用回调提供的异常恢复协程
continuation.resumeWithException(cause)
}
}
mockApi.register(callback)
continuation.invokeOnCancellation{
mockApi.unregister(callback)
}
}
class MockApi : Api {
private var callback: Callback? = null
override fun register(callback: Callback) {
this.callback = callback
}
override fun unregister(callback: Callback) {
// 在取消时注销回调
this.callback = null
}
fun triggerCallback(value: String) {
runBlocking {
delay(2000)
println("Send Completed")
callback?.onCompleted(value)
}
}
fun triggerError(cause: Throwable) {
runBlocking {
delay(2000)
println("Send ApiError")
callback?.onApiError(cause)
}
}
}
interface Api {
fun register(callback: Callback)
fun unregister(callback: Callback)
}
interface Callback {
fun onCompleted(value: String)
fun onApiError(cause: Throwable)
}
// 在协程中执行
fun main():Unit =runBlocking{
//开个子协程
launch {
try {
val result = awaitCallback()
println("Callback completed with result: $result")
} catch (e: Throwable) {
println("Callback failed with exception: $e")
}
//等待回调的结果返回完成 继续执行
println("Continue to perform the task ")
}
// 模拟成功的回调
mockApi.triggerCallback("Success!")
//mockApi.triggerError(Throwable("Error"))
}
Send Completed
onCompleted Success!
Callback completed with result: Success!
Continue to perform the task
withContext:
在不同的协程上下文中执行挂起函数。它的作用是在指定的协程上下文中执行一个挂起函数块,并在该块执行完成后返回结果
suspend fun exampleFunction() = withContext(Dispatchers.IO) {
// 在 IO 线程中执行耗时操作,例如网络请求或文件 I/O
delay(1000) // 模拟耗时操作
return@withContext "Result from withContext"
}
fun main() = runBlocking {
val result = exampleFunction()
println(result)
}
Result from withContext
withTimeout :
挂起函数并在设置超时时间,如果超过了指定的时间,将抛出 TimeoutCancellationException 异常。这有助于在异步操作中设置超时,防止长时间等待或阻塞。
suspend fun performAsyncTask(): String {
delay(3000) // 模拟一个耗时的异步任务
return "Task completed successfully!"
}
fun performBlockingTask(): String {
Thread.sleep(3000) // 模拟一个阻塞任务
return "Blocking task completed successfully!"
}
fun main() = runBlocking {
try {
val result = withTimeout(2000) {
performAsyncTask()
//performBlockingTask()
}
println(result)
} catch (e: TimeoutCancellationException) {
println("Task timed out!")
}
}
Task timed out!
//Blocking task completed successfully!
withTimeoutOrNull :
在协程中设置超时。它的作用是在指定的时间内运行一个挂起的代码块,并在超时时返回 null,而不是抛出异常。
超时会导致代码块内正在执行的代码被取消,并且在代码块内部激活或下一次激活可取消的挂起函数时,会抛出 TimeoutCancellationException 异常文章来源:https://www.toymoban.com/news/detail-772081.html
runBlocking {
val result = withTimeoutOrNull(3000) {
// 在此处执行可能耗时的操作
delay(5000) // 模拟一个长时间的操作
"Operation completed"
}
if (result != null) {
println("Success: $result")
} else {
println("Timeout occurred")
}
}
Timeout occurred
yield:
将当前协程的执行权交出,让同一调度器上的其他协程有机会执行。它是一种协作式多任务处理的机制,允许协程在不阻塞线程的情况下进行切换。文章来源地址https://www.toymoban.com/news/detail-772081.html
suspend fun launchWorker() = CoroutineScope(Dispatchers.Default).launch{
repeat(10) {
println("Worker coroutine is working $it")
delay(50)
// 使用 yield 让出执行权
yield()
}
}
fun main() = runBlocking {
val job = launchWorker()
// 主协程做一些其他事情
repeat(5) {
println("Main coroutine is doing some work $it")
delay(100)
}
// 等待工作协程完成
job.cancel()
}
Main coroutine is doing some work 0
Worker coroutine is working 0
Worker coroutine is working 1
Main coroutine is doing some work 1
Worker coroutine is working 2
Worker coroutine is working 3
Main coroutine is doing some work 2
Worker coroutine is working 4
Worker coroutine is working 5
Main coroutine is doing some work 3
Worker coroutine is working 6
Main coroutine is doing some work 4
Worker coroutine is working 7
Worker coroutine is working 8
Worker coroutine is working 9
到了这里,关于Kotlin 协程库v1.7.1的核心模块(kotlinx-coroutines-core)-- kotlinx.coroutines篇的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!