Kotlin协程中的Flow

本文深入探讨了Kotlin Flow的各种操作符,包括emit、collect、filter、map、transform、buffer、conflate、zip和combine等。通过实例展示了如何在协程中使用Flow进行数据处理,如线程切换、背压控制、状态管理和异常处理。同时,文章还提到了Flow与LiveData、SharedFlow和StateFlow的区别,并提供了实际应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

flow:emit发射数据

 lifecycleScope.launch {
            //TODO Flow是冷数据,不消费则不生产,只有调用collect()函数时才会发射数据
            //SharedFlow则是热流,会立即发射数据
            //StateFlow是SharedFlow的一个特殊变种,SharedFlow是Flow的一种特殊类型
            //StateFlow与LiveData比较接近,都有stateFlow.value=value
            //StateFlow必须传入一个默认值,可以有多个观察者
            flow {
                //TODO 上游发射数据
                Log.e(TAG, "emit1: start")
                emit(1)

                Log.e(TAG, "emit2: start")
                emit(2)

                Log.e(TAG, "emit3: start")
                emit(3)

                Log.e(TAG, "emit: all end")
            }.onEach {
                delay(2000)
                Log.e(TAG, "onEach:$it ")
            }.collect {
                //TODO 下游接收数据
                Log.e(TAG, "collect: $it")
                mBinding.textView.text = "接收数据为:$it"
            }

//            TODO  末端操作符
//            集合类型转换操作:包括 toList、toSet 等。
//            聚合操作:包括将 Flow 规约到单值的 reduce、fold 等操作,
//                    以及获得单个元素的操作包括 single、singleOrNull、first 等。
//              toList 转List集合
//              toSet 转Set集合
//              first 取第一个值
//              single 确保流发射单个值
//              reduce 如果发射的是int 最终会得到一个int 可以累加操作
//              fold reduce拓展 可以自定义返回类
        }

flowOf:内部封装的还是原先的emit函数

 lifecycleScope.launch {
            //TODO 自动向下游发送数据 内部封装的还是原先的emit函数
            flowOf("1", "2", "3", "4", "5")
                .onEach {
                    delay(2000)
                    Log.e(TAG, "onEach: $it")
                }
                .collect {
                    Log.e(TAG, "collect: $it")
                    mBinding.textView.text = "接收数据为:$it"
                }
        }

Flow Status:

  • onStart eg:显示对话框
  • catch eg:显示错误UI
  • onCompletion eg:隐藏对话框
  lifecycleScope.launch {
            //TODO List 转成 Flow
            mList.asFlow()
                .onEach {
                    delay(2000)
                    Log.e(TAG, "onEach: $it")

                    //catch
                    throw NullPointerException()
                }
                .onStart {
                    Log.e(TAG, "onStart: ")
                    showLoading("loading...")
                }
                .onCompletion {
                    Log.e(TAG, "onCompletion: ")
                    dismissLoading()
                }
                .catch {
                    Log.e(TAG, "catch: ")
                    mBinding.textView.text = "数据出错"
                }

                .collect {
                    Log.e(TAG, "collect: $it")
                    mBinding.textView.text = "接收数据为:$it"
                }
        }

flowOn:线程切换(flow为IO,其他为Main)

    lifecycleScope.launch {
            Log.e(TAG, "flow:${Thread.currentThread()}")
            flow {
                Log.e(TAG, "emit start:${Thread.currentThread()}")
                emit("1")
                Log.e(TAG, "emit 1:${Thread.currentThread()}")
                emit("2")
                Log.e(TAG, "emit 2:${Thread.currentThread()}")
                emit("3")
                Log.e(TAG, "emit 3:${Thread.currentThread()}")
                emit("4")
                Log.e(TAG, "emit 4:${Thread.currentThread()}")
                emit("5")
                Log.e(TAG, "emit 5:${Thread.currentThread()}")
                emit("6")
                Log.e(TAG, "emit 6:${Thread.currentThread()}")
            }
                .flowOn(Dispatchers.IO)
                .onStart {
                    Log.e(TAG, "onStart:${Thread.currentThread()}")
                    showToast("开始")
                }
                .filter {
                    Log.e(TAG, "filter:${Thread.currentThread()}")
                    it != "2"
                }
                .map {
                    Log.e(TAG, "map:${Thread.currentThread()}")
                    "转换$it"
                }
                .transform<String,Int>{
                    Log.e(TAG, "transform1:${Thread.currentThread()}")
                    emit(  it.length)
                    Log.e(TAG, "transform2:${Thread.currentThread()}")
                }
//                .zip(f1) { a, b ->
//                    Log.e(TAG, "zip:${Thread.currentThread()}")
//                    "本流$a:其他流$b"
//                }

                .onCompletion {
                    Log.e(TAG, "onCompletion:${Thread.currentThread()}")
                    showToast("结束")
                }
                .catch {
                    Log.e(TAG, "catch:${Thread.currentThread()}")
                    showToast("异常")
                }
                .collect {
                    Log.e(TAG, "collect:${Thread.currentThread()}")
                    Log.e(TAG, "collect:${it}")

                    mBinding.textView.text = it.toString()
                }
        }

cancel:取消流

   val job = lifecycleScope.launch {

            Log.e(TAG, "flow:${Thread.currentThread()}")
            flow {
                Log.e(TAG, "emit start:${Thread.currentThread()}")
                emit("1")
                Log.e(TAG, "emit 1:${Thread.currentThread()}")
                emit("2")
                Log.e(TAG, "emit 2:${Thread.currentThread()}")
                emit("3")
                Log.e(TAG, "emit 3:${Thread.currentThread()}")
                emit("4")
                Log.e(TAG, "emit 4:${Thread.currentThread()}")
                emit("5")
                Log.e(TAG, "emit 5:${Thread.currentThread()}")
                emit("6")
                Log.e(TAG, "emit 6:${Thread.currentThread()}")
            }
                .flowOn(Dispatchers.IO)
                .onStart {
                    Log.e(TAG, "onStart:${Thread.currentThread()}")
                    showToast("开始")
                }
                .onCompletion {
                    Log.e(TAG, "onCompletion:${Thread.currentThread()}")
                    showToast("结束")
                }
                .catch {
                    Log.e(TAG, "catch:${Thread.currentThread()}")
                    showToast("异常")
                }
                .collect {
                    Log.e(TAG, "collect:${Thread.currentThread()}")
                    Log.e(TAG, "collect:${it}")

                    mBinding.textView.text = it.toString()
                }
        }
        job.cancel()

filter :过滤操作符

 lifecycleScope.launch {
            //TODO List 转成 Flow
            mList.asFlow()
                .onEach {
                    delay(2000)
                    Log.e(TAG, "onEach: $it")
                }
                .filter {
                    //TODO 数据过滤操作符
                    //只发送能被2整除的数据
                    Log.e(TAG, "filter: $it")
                    it.toInt() % 2 == 0
                }
                .collect {
                    Log.e(TAG, "collect: $it")
                    mBinding.textView.text = it
                }
        }

filterNot :过滤操作符

 lifecycleScope.launch {
            //TODO List 转成 Flow
            mList.asFlow()
                .onEach {
                    delay(2000)
                    Log.e(TAG, "onEach: $it")
                }
                .filterNot {
                    //TODO 数据过滤操作符
                    //只发送不能被2整除的数据
                    Log.e(TAG, "filterNot: $it")
                    it.toInt() % 2 == 0
                }
                .collect {
                    Log.e(TAG, "collect: $it")
                    mBinding.textView.text = it
                }
        }

transform:转换操作符(需主动发送数据)

  lifecycleScope.launch {
            //TODO List 转成 Flow
//            mList.asFlow()
            flow {
                //TODO 上游发射数据
                Log.e(TAG, "emit1: start")
                emit("1")

                Log.e(TAG, "emit2: start")
                emit("2")

                Log.e(TAG, "emit3: start")
                emit("3")

                Log.e(TAG, "emit: all end")
            }
                .onEach {
                    delay(2000)
                    Log.e(TAG, "onEach: $it")
                }
                .transform<String, Int> {
                    //TODO 转化操作符 转化完成后需主动发送数据
                    Log.e(TAG, "transform: $it")
                    val value = it.toInt() + 100
                    emit(value)
                }
                .collect {
                    Log.e(TAG, "collect: $it")
                    mBinding.textView.text = it.toString()
                }
        }

map:转换操作符

  lifecycleScope.launch {
            //TODO List 转成 Flow
            mList.asFlow()
                .onEach {
                    delay(2000)
                    Log.e(TAG, "onEach: $it")
                }
                .map {
                    //TODO 数据类型转换操作 内部实现transform
                    Log.e(TAG, "map: $it")
                    it.toInt() + 100
                }
                .collect {
                    Log.e(TAG, "collect: $it")
                    mBinding.textView.text = it.toString()
                }
        }

take: 截取操作符

  lifecycleScope.launch {
            //TODO List 转成 Flow
            mList.asFlow()
                .onEach {
                    delay(2000)
                    Log.e(TAG, "onEach: $it")
                }
                //TODO 截取操作符,截取N位发射数据
                .take(2)
                .collect {
                    Log.e(TAG, "collect: $it")
                    mBinding.textView.text = it.toString()
                }
        }

buffer:背压操作符

 lifecycleScope.launch {
            //TODO List 转成 Flow
            flow {
                //TODO 上游发射数据
                Log.e(TAG, "emit1: start")
                emit(1)

                Log.e(TAG, "emit2: start")
                emit(2)

                Log.e(TAG, "emit3: start")
                emit(3)

                Log.e(TAG, "emit: all end")
            }
                .onEach {
//                    delay(2000)
                    Log.e(TAG, "onEach: $it")
                }
                //TODO 背压:.buffer() 先emit all 再collect
//                .buffer()
                //TODO 背压:.buffer(0) 先emit 1和2 -> collect 1和2  再emit 3 -> collect 3
                .buffer(0)
                .collect {
                    Log.e(TAG, "collect: $it")
                    mBinding.textView.text = it.toString()
                }
        }

conflate

 lifecycleScope.launch {
            //TODO List 转成 Flow
            flow {
                //TODO 上游发射数据
                for(i in 1..30) {
                    delay(100)
                    emit(i)
                }
            }
                //TODO 仅保留最新的值,无论上游发射多少数据,下游只会接收最新值
                .conflate()
                .onEach {
                    delay(2000)
                    Log.e(TAG, "onEach: $it")
                }

                .collect {
                    Log.e(TAG, "collect: $it")
                    mBinding.textView.text = it.toString()
                }
        }

zip:流合并操作符

  val flowOther = (101..110).asFlow()
        lifecycleScope.launch {
            //TODO List 转成 Flow
            mList.asFlow()
                .onEach {
                    delay(2000)
                    Log.e(TAG, "onEach: $it")
                }
                //TODO 合并其他流,本流发射数 < 其他流的发射数时,合并完的次数为本流的次数
                .zip(flowOther){a,b->
                    "本流$a:其他流$b"
                }
                .collect {
                    Log.e(TAG, "collect: $it")
                    mBinding.textView.text = it.toString()
                }
        }

combine:流组合操作符

 val flowOther = (101..110).asFlow()
        lifecycleScope.launch {
            //TODO List 转成 Flow
            mList.asFlow()
                .onEach {
                    delay(2000)
                    Log.e(TAG, "onEach: $it")
                }
                //TODO 组合流---  组合有点不规律
                .combine(flowOther){a,b->
                    "本流$a:其他流$b"
                }
                .collect {
                    Log.e(TAG, "collect: $it")
                    mBinding.textView.text = it.toString()
                }
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值