概述
可以利用中间运算符在不使用值的情况下修改数据流。中间运算符可以接连应用,形成链式运算,在数据项被发送到数据流时延迟执行。
其中操作符还分为三大类:
- 创建操作符
- 中间操作符
- 末端操作符
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m20UOOOF-1670402776711)(/Users/apple/Downloads/job_files/flow/Xnip2022-11-20_15-33-21.jpg )]
创建操作符
flow
val f = flow {
emit(1)
emitAll(flowOf(1, 2, 3))
}
// output
1
1
2
3
创建 Flow
的基本方法. 使用 emit
发射单个值使用 emitAll
发射一个流 ,类似 list.addAll(list)
flowOf
快速创建 flow
, 类似 listOf()
val f2 = flowOf("A", "B", "C")
// output
A
B
C
asFlow
将其他数据转换成 普通的flow
,一般是集合向Flow
的转换
kotlin 标准库中提供了基本数据类型相关扩展方法,其中 Map
类型不能直接使用asFlow()
需要转换成其支持的类型,再使用 asFlow()
.
fun testAsFlow3() {
// Range 类型
val flow1 = IntRange(1, 100).asFlow()
val flow2 = LongRange(1L, 1000L).asFlow()
// Array 类型
val flow3 = intArrayOf(1, 2, 3).asFlow()
val flow4 = longArrayOf(1L, 2L, 3L).asFlow()
val flow5 = arrayOf("A", "B", "C").asFlow()
// Sequence 类型
val flow6 = sequenceOf("X", "Y", "Z").asFlow()
// Iterable 类型
val flow7 = listOf(1, 2, 3).asFlow()
val flow8 = setOf("E", "G", "C").asFlow()
// Iterator 类型
val flow9 = iterator<Int> {
}.asFlow()
// Map 类型
val map = hashMapOf(Pair("A", 1), Pair("B", 2))
val flow10 = map.asIterable().asFlow()
val flow11 = map.asSequence().asFlow()
val flow12 = map.iterator().asFlow()
}
callbackFlow
将回调方法改造成 flow
, 类似 suspendCoroutine
例如我们有以下,利用 RequestManager
和 RequestCallBack
模拟数据加载情况,将回调改造成支持 Flow
interface RequestCallBack {
fun onStart()
fun onSuccessFul(value: Int)
fun onError(e: Throwable)
fun onCompleted()
}
object RequestManager {
private val callBacks = mutableListOf<RequestCallBack>()
fun addRequestCallBack(callBack: RequestCallBack) {
callBacks.add(callBack)
}
fun removeRequestCallBack(callBack: RequestCallBack) {
callBacks.remove(callBack)
}
fun request() {
callBacks.forEach {
it.onStart()
}
try {
val value = Random.nextInt()
if (value % 2 == 0) {
throw IllegalStateException("value % 2 != 0")
}
callBacks.forEach {
it.onSuccessFul(value)
}
} catch (e: Exception) {
callBacks.forEach {
it.onError(e)
}
}
callBacks.forEach {
it.onCompleted()
}
}
}
利用callbackFlow
函数,改造如下:
fun testCallBackFlow(): Flow<Int> = callbackFlow {
val callback = object : RequestCallBack {
override fun onStart() {
}
override fun onSuccessFul(value: Int) {
trySend(value) // 将数据发送到 flow中
}
override fun onError(e: Throwable) {
close(e) // 抛出异常关闭
close() // 正常关闭, 不抛出异常
}
override fun onCompleted() {
}
}
RequestManager.addRequestCallBack(callback)
RequestManager.request()
// 关闭之后回调
awaitClose {
RequestManager.removeRequestCallBack(callback)
}
}
- 调用
send()
或trySend()
将数据发送至Flow
中 - 在回调结束调用
close()
关闭管道、其中close()
传入异常将末端收集不到出错前数据,如果不传则可以正常收集到. awitClose
扩展方法在Flow
管道close()
之后调用,可以在此处做数据回收等工作。
与 flow
构建器不同,callbackFlow
允许通过 send
函数从不同 CoroutineContext
发出值
在协程内部,callbackFlow
会使用通道,它在概念上与阻塞队列非常相似。通道都有容量配置,限定了可缓冲元素数的上限。在 callbackFlow
中所创建通道的默认容量为 64 个元素。当您尝试向完整通道添加新元素时,send
会将数据提供方挂起,直到新元素有空间为止.
emptyFlow
val f3 = emptyFlow<Int>()
返回一个空流。
channelFlow
在一般的flow
在构造代码块中不允许切换线程,ChannelFlow
则允许内部切换线程
val f4 = channelFlow<Int> {
send(1)
withContext(Dispatchers.IO) {
send(2)
}
withContext(Dispatchers.Default) {
send(3)
}
}
// output
1
2
3
变换操作符
map
将发出的值 进行变换,lambda
的返回值为最终发送的值
val flowMap = flow {
emit(true)
}.map {
return@map it.toString()
}
mapLatest
转换原始流数据,当原始流发出新值时,将取消对先前值的转换块的计算。
val flowMapLatest = flow {
emit("a")
delay(100)
emit("b")
}.mapLatest {
value ->
println("Started computing $value")
delay(200)
"Computed $value"
}
// output
Started computing a
Started computing b
Computed b
mapNotNull
对数据流控制,仅发送 map
后不为空的值
val flowMapNoNull = flow {
emitAll(flowOf("A", "B"))
}.mapNotNull {
if (it == "B") {
it
} else {
null
}
}
// output
B
transform
对发出的值 进行变换 。区别于map
, transform
的接收者是FlowCollector
,因此它非常灵活,可以变换、跳过它或多次发送。
val flowTransform = flow {
emi