拒绝重复造轮子:我写了一个生产级的 Kotlin 协程与 Flow 工具库(CoroutineKit)

拒绝重复造轮子:我写了一个生产级的 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 引入:

kotlin 复制代码
dependencies {
    implementation("com.yangcyzhang:coroutinekit:0.1.0")
}

🚀 核心功能亮点与使用指南

1. 安全的 suspendRunCatching ------ 告别协程取消失效

在标准库中,runCatching 会捕获 Throwable。如果不小心在协程中包裹了它,CancellationException(协程取消的信号)也会被捕获,导致协程无法正常取消。

CoroutineKit 提供的 suspendRunCatching 内部严格放行了 CancellationException

kotlin 复制代码
val result: Result<User> = suspendRunCatching {
    userRepository.fetchUser(id)
}

result.onSuccess { user -> render(user) }
      .onFailure { e -> showError(e) }

2. 带超时兜底的 withTimeoutOrDefault

在进行某些非核心数据的网络请求时,如果超时我们希望直接返回一个默认值而不是抛出异常阻断流程:

kotlin 复制代码
val data = withTimeoutOrDefault(timeMillis = 3_000, defaultValue = emptyList()) {
    networkService.fetchFeed()
}

3. UI 按钮防抖利器 ------ throttleFirst

针对频繁点击、重复提交等场景,Flow 扩展了 throttleFirst

kotlin 复制代码
buttonClickFlow
    .throttleFirst(windowDuration = 500) // 500ms 内只响应第一次点击
    .onEach { handleClick() }
    .launchIn(viewModelScope)

4. 强大的带延迟重试 ------ retryWithDelay

支持指数退避(Exponential Backoff)策略的 Flow 重试操作符:

kotlin 复制代码
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 立即重试):

kotlin 复制代码
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 接口:

kotlin 复制代码
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,每次提交都会自动运行测试,确保代码的健壮性。

bash 复制代码
# 运行单元测试
./gradlew :coroutinekit:test

欢迎交流与共建

如果你也经常在项目中遇到类似的协程样板代码,欢迎访问 GitHub 仓库了解详情、提出建议或贡献代码:

相关推荐
恋猫de小郭2 小时前
Flutter GSoC 2026 提案进度解读,补上 DevTools、FFI 和原生平台的关键缺口
android·前端·flutter
2501_915909062 小时前
怎么用 FlutterFlow 把应用发布到 App Store?
android·ios·小程序·https·uni-app·iphone·webview
峥嵘life2 小时前
2026华为AI码道 CodeArts 使用分享:Windows端 + 服务器CLI 实战总结
android·大数据·开发语言·python
yxlalm2 小时前
对话记忆持久化-Redis热与MySQL冷
android·redis·mysql
1570925113411 小时前
Android进阶之光:HTTP协议原理深度解析
android·网络协议·http
终端安全笔记12 小时前
安卓五品牌通道差在哪:监管通道拆解
android
v_348360876212 小时前
Android native端 堆栈打印
android·算法
一笑的小酒馆13 小时前
AndroidKMP之导航和WebView
android