kotlin创建和启动协程

本文介绍了图形架构中的关键组件,包括窗口服务器、字体位图服务器、多媒体服务器及其在应用程序中的作用。详细讨论了图形设备(如屏幕和打印机)与图形上下文的概念,并提供了具体的类名示例,如 CFbsBitmapDevice 和 CWindowGc 的使用方法。

协程构建器

launch和async构建器都用来启动新协程。

  • launch,返回一个Job并且不附带任何结果。
  • async,返回一个Deferred,Deferred也是一个Job,可以使用.await()在一个延期的值上得到最终的结果。
  • launch 是非阻塞的。
  • runBlocking 是阻塞的,一般用在测试中,会阻塞当前线程,会等到包裹的子协程都执行完毕才退出。
  • 多个 withContext 任务是串行的, 且withContext 可直接返回耗时任务的结果。
  • 多个 async 任务是并行的,async 返回的是一个Deferred<T>,需要调用其await()方法获取结果。await() 只有在 async 未执行完成返回结果时,才会挂起协程。若 async 已经有结果了,await() 则直接获取其结果并赋值给变量,此时不会挂起协程。
构建器是否立即启动?串行?并行?是否阻塞当前线程?返回结果
launch根据包裹的子协程类型而定Job对象
async任务之间是并行Deferred,可以用await()方法获取结果
runBlocking根据包裹的子协程类型而定阻塞子协程都执行完毕后才退出
withContext不是任务之间是串行可以直接返回耗时任务结果,协程体最后一行内容

doAsync和async

  • doAsync 的源码实现是基于Java的 Future 类进行异步处理和通过Handler进行线程切换 ,从而封装的一个扩展函数方便线程切换。
  • doAsync 与 async 关系不大, doAsync并没有用到协程库中的内容。
  • 可以通过 uiThread { } 切换回到主线程。
btn.setOnClickListener {
    doAsync {
        Log.e("TAG", " doAsync...   [当前线程为:${Thread.currentThread().name}]")
        uiThread {
            Log.e("TAG", " uiThread....   [当前线程为:${Thread.currentThread().name}]")
        }
    }
}

GlobalScope.launch

GlobalScope.launch启动的协程默认运行在Default调度器上

关键说明

  • 默认调度器‌:当使用 GlobalScope.launch { ... } 且‌未显式指定调度器‌时,协程使用 Dispatchers.Default 作为其调度器。‌
  • Dispatchers.Default 是一个‌共享的后台线程池‌,适用于‌CPU 密集型任务‌(如计算、数据处理等)。
  • Dispatchers.Default不是主线程,不会阻塞 UI 线程,适合在后台执行耗时计算。

示例验证

GlobalScope.launch { 
    println("Thread: ${Thread.currentThread().name}")
    // 输出线程名称通常包含 "DefaultDispatcher-worker-" 
}

注意事项

  • 不推荐在生产代码中使用 GlobalScope‌,因为它创建的协程生命周期与应用一致,容易导致‌内存泄漏‌或‌资源泄露‌。应优先使用作用域(如 lifecycleScopeviewModelScope 或自定义 CoroutineScope)来管理协程生命周期。
  • 若需执行 IO 操作,应显式切换到 Dispatchers.IO;若需更新 UI,则应使用 Dispatchers.Main

总结

  • 默认调度器‌:Dispatchers.Default
  • 适用场景‌:后台 CPU 密集型任务
  • 最佳实践‌:避免直接使用 GlobalScope,改用结构化并发的作用域管理协程。

lifecycleScope.launch

lifecycleScope.launch启动的协程默认运行在Main.immediate 调度器上

关键说明

  • 默认调度器‌:lifecycleScope 是 Android Jetpack 提供的生命周期感知协程作用域,其底层协程上下文(CoroutineContext)默认包含 SupervisorJob() + Dispatchers.Main.immediate‌。
  • Dispatchers.Main.immediate 与 Dispatchers.Main 一样运行在主线程;
  • Dispatchers.Main.immediate 更高效‌:如果当前已在主线程,则立即执行;否则排队等待主线程空闲。
  • 生命周期绑定‌:协程会随 Activity/Fragment 的 onDestroy() 自动取消,避免内存泄漏。

实践建议

  • 若需执行耗时操作(如网络请求、文件读写),应显式切换调度器:
    lifecycleScope.launch { 
        val data = withContext(Dispatchers.IO) { 
            fetchData() 
        } 
        textView.text = data // 切回主线程更新 UI 
    }
  • 不要‌在 lifecycleScope.launch { } 中直接执行阻塞主线程的操作,否则会导致 UI 卡顿。

总结:‌lifecycleScope.launch默认运行在主线程(Dispatchers.Main.immediate),耗时任务需手动切换到 Dispatchers.IO 或 Dispatchers.Default‌。

viewModelScope .launch

viewModelScope 默认运行在 Dispatchers.Main.immediate 调度器上‌,该调度器基于主线程(UI 线程),用于执行与 UI 相关的轻量级操作。

关键说明

  • 默认调度器‌:viewModelScope 使用的是 Dispatchers.Main.immediate,这是 Dispatchers.Main 的一个优化版本,在主线程上尽可能立即执行任务,避免不必要的线程切换 。
  • 线程特性‌:虽然运行在主线程,但 ‌不应执行耗时操作‌(如网络请求、数据库读写),否则会阻塞 UI,导致卡顿 。
  • 切换线程‌:若需执行后台任务,应显式使用 withContext(Dispatchers.IO) 或 withContext(Dispatchers.Default) 切换线程 。

注意事项

  • Dispatchers.Main.immediate 与 Dispatchers.Main 行为基本一致,但在主线程已处于调度循环中时,会更高效地立即执行。
  • ViewModel 的生命周期长于 Activity/Fragment,因此 viewModelScope 在 ViewModel 被清除(如 Activity 完全关闭)时会自动取消所有子协程,避免内存泄漏。

协程的启动模式

    启动模式通过start参数传递。

  • CoroutineStart.DEFAULT:协程创建后立即调度。在调度前如果协程被取消,进入取消响应状态。
  • CoroutineStart.ATOMIC:协程创建后立即调度。协程执行到第一个挂起点之前不响应取消。立即调度不等于立即执行。
  • CoroutineStart.LAZY:协程创建后不立即调度。只有主动调用协程的start、join或者await等函数时才会开始调度。如果调度前被取消,该协程进入异常结束状态。
  • CoroutineStart.UNDISPATCHED:协程创建后立即在当前函数调用栈中执行,直到遇到第一个真正的挂起点。
@Test
fun `test start mode`() = runBlocking {
    val job = async(context = Dispatchers.IO, start = CoroutineStart.UNDISPATCHED) {
        println("thread:"+ Thread.currentThread().name)
    }
}
//上面输出的线程名字是主线程,因为UNDISPATCHED会立即在当前线程中执行,而runBlocking是在主线程中
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值