Kotlin - Flow 中创建流的方式

1. flow

  • 描述: 创建一个冷流,从给定的 suspendable block 中生成值。冷流意味着每次应用终端操作时,block 会被调用。
  • 使用场景: 适用于自定义流的生成。
fun fibonacci(): Flow<BigInteger> = flow {
    var x = BigInteger.ZERO
    var y = BigInteger.ONE
    while (true) {
        emit(x)
        val temp = x
        x = y
        y += temp
    }
}

// 使用
fibonacci().take(10).collect { println(it) }

2. asFlow (无参)

  • 描述: 将一个函数转换为产生单个值的冷流。
  • 使用场景: 适用于将普通函数转换为流。
val singleValueFlow = { 42 }.asFlow()

// 使用
singleValueFlow.collect { println(it) } // 输出: 42

3. asFlow (带 suspend)

  • 描述: 将一个 suspend 函数转换为产生单个值的冷流。
  • 使用场景: 适用于将 suspend 函数转换为流。
suspend fun remoteCall(): String = "Hello, World!"

fun remoteCallFlow(): Flow<String> = ::remoteCall.asFlow()

// 使用
remoteCallFlow().collect { println(it) } // 输出: Hello, World!

4. Iterable.asFlow

  • 描述: 从给定的可迭代对象创建一个冷流。
  • 使用场景: 适用于将集合转换为流。
val listFlow = listOf(1, 2, 3).asFlow()

// 使用
listFlow.collect { println(it) } // 输出: 1, 2, 3

5. Iterator.asFlow

  • 描述: 从给定的迭代器创建一个冷流。
  • 使用场景: 适用于将迭代器转换为流。
val iteratorFlow = listOf(1, 2, 3).iterator().asFlow()

// 使用
iteratorFlow.collect { println(it) } // 输出: 1, 2, 3

6. Sequence.asFlow

  • 描述: 从给定的序列创建一个冷流。
  • 使用场景: 适用于将序列转换为流。
val sequenceFlow = sequenceOf(1, 2, 3).asFlow()

// 使用
sequenceFlow.collect { println(it) } // 输出: 1, 2, 3

7. flowOf

  • 描述: 创建一个流,产生指定的元素。
  • 使用场景: 适用于快速生成多个值的流。
val flowOfNumbers = flowOf(1, 2, 3)

// 使用
flowOfNumbers.collect { println(it) } // 输出: 1, 2, 3

8. emptyFlow

  • 描述: 返回一个空流。
  • 使用场景: 适用于需要返回无元素的流的情况。
val empty = emptyFlow<Int>()

// 使用
empty.collect { println(it) } // 不会输出任何东西

9. Array.asFlow

  • 描述: 从给定数组创建一个冷流。
  • 使用场景: 适用于将数组转换为流。
val arrayFlow = arrayOf(1, 2, 3).asFlow()

// 使用
arrayFlow.collect { println(it) } // 输出: 1, 2, 3

10. IntArray.asFlow

  • 描述: 从给定的整数数组创建一个冷流。
  • 使用场景: 适用于将整数数组转换为流。
val intArrayFlow = intArrayOf(1, 2, 3).asFlow()

// 使用
intArrayFlow.collect { println(it) } // 输出: 1, 2, 3

11. LongArray.asFlow

  • 描述: 从给定的长整型数组创建一个冷流。
  • 使用场景: 适用于将长整型数组转换为流。
val longArrayFlow = longArrayOf(1L, 2L, 3L).asFlow()

// 使用
longArrayFlow.collect { println(it) } // 输出: 1, 2, 3

12. IntRange.asFlow

  • 描述: 从给定的整数范围创建一个冷流。
  • 使用场景: 适用于将范围转换为流。
val rangeFlow = (1..3).asFlow()

// 使用
rangeFlow.collect { println(it) } // 输出: 1, 2, 3

13. LongRange.asFlow

  • 描述: 从给定的长整型范围创建一个冷流。
  • 使用场景: 适用于将长整型范围转换为流。
val longRangeFlow = (1L..3L).asFlow()

// 使用
longRangeFlow.collect { println(it) } // 输出: 1, 2, 3

14. channelFlow

  • 描述: 创建一个允许并发发送元素的冷流。可以使用 ProducerScope 发送元素。
  • 使用场景: 适用于需要从多个协程并发发送数据的情况。
fun <T> channelFlowExample(): Flow<T> = channelFlow {
    launch {
        send("Hello")
    }
    launch {
        send("World")
    }
}

// 使用
channelFlowExample<String>().collect { println(it) } // 输出: Hello, World (顺序可能不同)

15. callbackFlow

  • 描述: 创建一个冷流,允许从异步回调中发送元素。使用 ProducerScope 发送元素。
  • 使用场景: 适用于将基于回调的 API 转换为流。
fun flowFromCallbackApi(api: CallbackBasedApi): Flow<String> = callbackFlow {
    val callback = object : Callback {
        override fun onNextValue(value: String) {
            trySend(value).isSuccess
        }

        override fun onCompleted() {
            close()
        }
    }
    api.register(callback)
    awaitClose { api.unregister(callback) }
}

// 使用
flowFromCallbackApi(myApi).collect { println(it) }

总结

这些函数提供了灵活的方式来创建流,适应各种场景,从简单的值到复杂的异步数据流。通过理解这些函数的使用,可以有效地处理异步数据。

### Kotlin Flow 使用指南 #### 创建 `Flow` `Flow` 是一种用于表示异步数据的类型,在 Kotlin 中由 kotlinx.coroutines 库提供支持。可以使用多种方式创建 `Flow` 对象。 最简单的方式之一是利用 `flow {}` 构建器函数,它允许发送多个值给下游消费者: ```kotlin import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow val simpleFlow: Flow<String> = flow { emit("Hello, world!") // 发射第一个字符串 } ``` 另一种常见的做法是从集合或其他序列转换而来;例如,可以通过调用 `.asFlow()` 扩展方法把列表转成 `Flow` 实例[^1]。 #### 收集 `Flow` 为了获取来自 `Flow` 的更新并对其作出反应,需要通过 `collect{}` 函数来进行收集操作。此过程通常发生在协程作用域内完成,因为 `Flow` 设计上就是用来处理长时间运行的任务或事件驱动型的数据源变化通知机制。 下面的例子展示了如何定义一个简单的 `Flow` 并对其进行监听: ```kotlin import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import kotlinx.coroutines.flow.collect fun main() = runBlocking<Unit> { val myFlow = flow { repeat(3) { i -> delay(100L) // 模拟耗时计算 emit("Item $i") } } myFlow.collect { value -> println(value) } // 输出每一项的结果 } ``` 这段代码会每隔 100ms 输出一次新产生的项目直到全部结束为止[^2]。 #### 处理错误与终止条件 当遇到异常情况时,`catch{}` 可以捕获上游抛出的所有未被捕获的 Throwable 类型对象,并给予适当处理而不至于让整个程崩溃掉。而如果想要提前停止接收更多的元素,则可借助于 `takeWhile{} / take(n)` 或者直接 throw Exception 来达到目的。 ```kotlin myFlow.catch { e -> /* 错误处理器 */ }.collect() // or try { myFlow.take(2).collect() } catch (e: Exception){ // handle exception here } ``` #### 结合其他库组件工作 除了基本功能外,还可以很容易地与其他框架集成起来一起运作——比如 Retrofit 网络请求、Room 数据库存储等。这些第三方类库往往也提供了相应的扩展 API 让开发者能够更加方便快捷地接入到自己的应用程序当中去[^4]。 #### 性能优势对比传统方案 相比于传统的回调模式或是 RxJava 这样的响应式编程解决方案来说,采用 Kotlin Flows 和 Coroutines 组合拳的形式不仅可以让代码看起来更为简洁直观易于维护,而且由于其内部实现了冷特性(即只有在有订阅者的情况下才会真正启动生产),所以在资源管理方面也会表现得更好一些[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值