这里系统梳理一下 android/kotlin 协程 的一些高级用法。会从 上下文管理、作用域控制、异常处理、性能优化、异步组合 等角度讲解,给你落地可用的示例。
1️⃣ 协程作用域(coroutinescope)与生命周期绑定
在 android 中,协程最好绑定到 生命周期,避免内存泄漏。
activity/fragment 中
class mainactivity : appcompatactivity() {
// 生命周期感知协程作用域
private val scope = lifecyclescope
override fun oncreate(savedinstancestate: bundle?) {
super.oncreate(savedinstancestate)
scope.launch {
val data = fetchdata()
updateui(data)
}
}
}- lifecyclescope:绑定 activity/fragment 生命周期,自动取消
- viewmodelscope:绑定 viewmodel 生命周期
手动创建 coroutinescope
private val customscope = coroutinescope(dispatchers.io + supervisorjob())
- 可以用
supervisorjob()避免一个子协程失败影响其它子协程 - 记得在
ondestroy()或oncleared()时customscope.cancel()
2️⃣ 异步组合:并发和串行
串行执行
val result1 = async { fetchdata1() }.await()
val result2 = async { fetchdata2() }.await()
val finalresult = combine(result1, result2)- 按顺序等待,每个任务完成后再执行下一个
并行执行
val deferred1 = async { fetchdata1() }
val deferred2 = async { fetchdata2() }
val result1 = deferred1.await()
val result2 = deferred2.await()- 并行启动,节省等待时间
并行 + awaitall
val results = awaitall(
async { fetchdata1() },
async { fetchdata2() },
async { fetchdata3() }
)3️⃣ 异常处理与结构化并发
try-catch
scope.launch {
try {
val result = fetchdata()
} catch (e: ioexception) {
handleerror(e)
}
}coroutineexceptionhandler
val handler = coroutineexceptionhandler { _, exception ->
log.e("coroutine", "caught $exception")
}
scope.launch(handler) {
val result = fetchdata()
}supervisorjob
- 父协程失败不影响子协程
val supervisor = supervisorjob() val scope = coroutinescope(dispatchers.io + supervisor)
4️⃣ 切换线程/调度器
- dispatchers.main → ui 操作
- dispatchers.io → 网络/文件操作
- dispatchers.default → cpu 密集型计算
scope.launch(dispatchers.io) {
val data = fetchdata()
withcontext(dispatchers.main) {
updateui(data)
}
}usewithcontext替代launch切换线程
- 便于返回值,避免嵌套
launch
5️⃣ 超时与取消
超时
try {
withtimeout(3000l) {
fetchdata()
}
} catch (e: timeoutcancellationexception) {
log.e("coroutine", "timeout")
}取消
val job = scope.launch {
fetchdata()
}
job.cancel() // 立即取消可取消挂起函数
- 网络、延迟、channel 等挂起函数是可取消的
- cpu 密集型循环需要手动检查
isactive:
for (i in 1..1000) {
if (!isactive) break
dowork()
}6️⃣ channels 与 flow(响应式数据流)
channel
- 类似队列,生产者和消费者解耦
val channel = channel<int>()
scope.launch {
for (i in 1..5) channel.send(i)
channel.close()
}
scope.launch {
for (i in channel) {
println(i)
}
}flow
- kotlin 原生的冷流,支持各种操作符
fun fetchnumbers(): flow<int> = flow {
for (i in 1..5) {
delay(100)
emit(i)
}
}
scope.launch {
fetchnumbers()
.map { it * 2 }
.filter { it > 5 }
.collect { println(it) }
}7️⃣ 高级技巧
- 组合多个异步源
val flow1 = flow { emit(fetchdata1()) }
val flow2 = flow { emit(fetchdata2()) }
flow1.combine(flow2) { d1, d2 -> d1 + d2 }
.collect { println(it) }- 懒启动的 async
val deferred = async(start = coroutinestart.lazy) { fetchdata() }
deferred.await() // 真正开始执行- 异常隔离
- 使用
supervisorjob()避免一个子协程挂掉影响整个父协程
- 使用
到此这篇关于android协程的用法大全的文章就介绍到这了,更多相关android协程用法内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论