Android Flow 操作符大全

概述

可以利用中间运算符在不使用值的情况下修改数据流。中间运算符可以接连应用,形成链式运算,在数据项被发送到数据流时延迟执行。

其中操作符还分为三大类:

  1. 创建操作符
  2. 中间操作符
  3. 末端操作符

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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

例如我们有以下,利用 RequestManagerRequestCallBack 模拟数据加载情况,将回调改造成支持 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)
    }
}
  1. 调用send()trySend() 将数据发送至 Flow
  2. 在回调结束调用 close() 关闭管道、其中close() 传入异常将末端收集不到出错前数据,如果不传则可以正常收集到.
  3. 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

对发出的值 进行变换 。区别于maptransform的接收者是FlowCollector ,因此它非常灵活,可以变换、跳过它或多次发送。

val flowTransform = flow {
   
    emi
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值