拒绝重复造轮子:我写了一个生产级的 Kotlin 协程与 Flow 工具库(CoroutineKit)
在日常的 Android 和 JVM 开发中,我们几乎每天都在和 Kotlin 协程(Coroutines)和 Flow 打交道。
虽然 Kotlin 协程官方已经提供了非常强大的基础能力,但在实际业务开发中,我们依然会频繁遇到一些“痛点”:
- 防抖节流:UI 上的连续点击需要做
throttleFirst,官方 Flow 并没有直接提供便捷的操作符。 - 异常吞噬:使用
runCatching时不小心把CancellationException给捕获并吞掉了,导致协程取消机制失效。 - 重试策略:网络请求失败后的重试(指数退避、固定延迟、特定异常过滤)每次都要写一堆重复的
try-catch和循环。 - 生命周期管理:在普通的 Repository 或后台服务中,需要一个带有
SupervisorJob且支持Closeable的安全CoroutineScope。 - Java 互操作:需要把挂起函数转成
CompletableFuture,或者把传统的监听器/回调(Callback)安全地转成Flow。
为了在各个项目中复用这些沉淀下来的最佳实践,我开源了一个轻量级、生产级的 Kotlin 协程工具库 —— CoroutineKit。
今天这篇文章,就带大家快速盘点一下 CoroutineKit 的核心功能以及它是如何帮我们优雅解决这些日常开发痛点的。
📦 快速引入
目前项目已发布 0.1.0 版本,支持通过 Maven Central 或 JitPack 引入:
dependencies {
implementation("com.yangcyzhang:coroutinekit:0.1.0")
}
🚀 核心功能亮点与使用指南
1. 安全的 suspendRunCatching —— 告别协程取消失效
在标准库中,runCatching 会捕获 Throwable。如果不小心在协程中包裹了它,CancellationException(协程取消的信号)也会被捕获,导致协程无法正常取消。
CoroutineKit 提供的 suspendRunCatching 内部严格放行了 CancellationException:
val result: Result<User> = suspendRunCatching {
userRepository.fetchUser(id)
}
result.onSuccess { user -> render(user) }
.onFailure { e -> showError(e) }
2. 带超时兜底的 withTimeoutOrDefault
在进行某些非核心数据的网络请求时,如果超时我们希望直接返回一个默认值而不是抛出异常阻断流程:
val data = withTimeoutOrDefault(timeMillis = 3_000, defaultValue = emptyList()) {
networkService.fetchFeed()
}
3. UI 按钮防抖利器 —— throttleFirst
针对频繁点击、重复提交等场景,Flow 扩展了 throttleFirst:
buttonClickFlow
.throttleFirst(windowDuration = 500) // 500ms 内只响应第一次点击
.onEach { handleClick() }
.launchIn(viewModelScope)
4. 强大的带延迟重试 —— retryWithDelay
支持指数退避(Exponential Backoff)策略的 Flow 重试操作符:
apiFlow
.retryWithDelay(
times = 3,
initialDelay = 200,
factor = 2.0,
predicate = { it is IOException } // 只在 IO 异常时重试
)
.collect { result -> process(result) }
5. 灵活的挂起函数重试策略 —— RetryPolicy
不仅 Flow 有重试,针对普通的挂起函数,CoroutineKit 提供了统一的 RetryPolicy(支持 Fixed 固定延迟、ExponentialBackoff 指数退避、Immediate 立即重试):
val result = withRetry(
policy = RetryPolicy.ExponentialBackoff(times = 4, initialDelayMs = 100),
predicate = { it is NetworkException }
) { attempt ->
println("Attempt $attempt")
apiCall()
}
6. 生命周期安全的 ManagedScope
如果你需要在普通类(如 Repository、Manager)中管理后台协程,可以使用 ManagedScope。它集成了 SupervisorJob 并实现了 Closeable 接口:
class MyRepository : Closeable {
private val scope = ManagedScope(Dispatchers.IO)
fn startSync() = scope.launch {
while (isActive) {
sync()
delay(30_000)
}
}
override fun close() = scope.close() // 一键安全取消所有子协程
}
7. Java 互操作桥梁 (JavaInterop)
- 挂起函数转
CompletableFuture:方便 Java 代码调用 Kotlin 协程。 - Callback 转
Flow:通用的callbackFlow封装,优雅接入各种传统监听器。
🧪 质量保障
作为一个生产级的小型工具库,项目配套了完整的单元测试(基于 kotlinx-coroutines-test 和 JUnit 5),并且集成了 GitHub Actions CI,每次提交都会自动运行测试,确保代码的健壮性。
# 运行单元测试
./gradlew :coroutinekit:test
欢迎交流与共建
如果你也经常在项目中遇到类似的协程样板代码,欢迎访问 GitHub 仓库了解详情、提出建议或贡献代码:
- GitHub 仓库:github.com/yangcyzhang…
- 如果觉得对你有帮助,欢迎点个 ⭐ 支持一下!