Kotlin 协程Flow 异步流 ① ( 以异步返回返回多个返回值 | 同步调用返回多个值的弊端 | 尝试在 sequence 中调用挂起函数返回多个返回值 | 协程中调用挂起函数返回集合 )
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin 协程Flow 异步流 ① ( 以异步返回返回多个返回值 | 同步调用返回多个值的弊端 | 尝试在 sequence 中调用挂起函数返回多个返回值 | 协程中调用挂起函数返回集合 )相关的知识,希望对你有一定的参考价值。
文章目录
一、以异步返回返回多个返回值
在 Kotlin 协程 Coroutine 中 , 使用 suspend 挂起函数 以异步的方式 返回单个返回值肯定可以实现 , 参考 【Kotlin 协程】协程的挂起和恢复 ① ( 协程的挂起和恢复概念 | 协程的 suspend 挂起函数 ) 博客 ;
如果要 以异步的方式 返回多个元素的返回值 , 可以使用如下方案 :
- 集合
- 序列
- Suspend 挂起函数
- Flow 异步流
二、同步调用返回多个值的弊端
同步调用返回集合和序列代码示例 : 同步调用函数时 , 如果函数耗时太长或者中途有休眠 , 则会阻塞主线程导致 ANR 异常 ;
package kim.hsl.coroutine
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 同步方法返回多个值
// 调用 " 返回 List 集合的函数 " , 并遍历返回值
listFunction().forEach
// 遍历打印集合中的内容
println(it)
// 同步调用 " 返回 Sequence 序列 " 时 , 线程会阻塞
sequenceFunction().forEach
// 遍历打印序列中的内容
println(it)
/**
* 返回 List 集合的函数
*/
fun listFunction(): List<Int> = listOf(0, 1, 2)
/**
* 返回 Sequence 序列
*/
fun sequenceFunction(): Sequence<Int> = sequence
for (i in 3..5)
// 每隔 0.5 秒向序列中存入一个值
Thread.sleep(500)
yield(i)
执行结果 :
2022-12-22 12:33:03.122 15427-15427/kim.hsl.coroutine I/System.out: 0
2022-12-22 12:33:03.123 15427-15427/kim.hsl.coroutine I/System.out: 1
2022-12-22 12:33:03.123 15427-15427/kim.hsl.coroutine I/System.out: 2
2022-12-22 12:33:03.661 15427-15427/kim.hsl.coroutine I/System.out: 3
2022-12-22 12:33:04.177 15427-15427/kim.hsl.coroutine I/System.out: 4
2022-12-22 12:33:04.703 15427-15427/kim.hsl.coroutine I/System.out: 5
三、尝试在 sequence 中调用挂起函数返回多个返回值
尝试使用 挂起函数 kotlinx.coroutines.delay
进行休眠 , 这样在挂起时 , 不影响主线程的其它操作 , 此时会报如下错误 ;
Restricted suspending functions can only invoke member or extension suspending functions
on their restricted coroutine scope
受限挂起函数只能在其受限的协程范围上调用成员或扩展挂起函数
下面分析上述报错原因 :
sequence
函数中 , 传入的是 @BuilderInference block: suspend SequenceScope<T>.() -> Unit
参数 , 该参数是一个函数 , 该函数 () -> Unit
是 SequenceScope
类型的扩展函数 ;
任意传入一个匿名函数 , 该函数被自动设置为 SequenceScope
类的扩展函数 , 在其中的任何调用都默认调用的是 SequenceScope
对象的方法 ;
在该匿名函数中 , 不能调用 SequenceScope
之外定义的挂起函数 , 这样做是为了保证该类的执行性能 ;
/**
* 构建一个[Sequence],一个接一个地懒惰地产生值。
*
* @see kotlin.sequences.generateSequence
*
* @sample samples.collections.Sequences.Building.buildSequenceYieldAll
* @sample samples.collections.Sequences.Building.buildFibonacciSequence
*/
@SinceKotlin("1.3")
public fun <T> sequence(@BuilderInference block: suspend SequenceScope<T>.() -> Unit): Sequence<T> = Sequence iterator(block)
在 SequenceScope
类上 , 有一个 @RestrictsSuspension
注解 , RestrictsSuspension
注解的作用是 限制挂起 , 在该类中不能调用其它的挂起函数 , 这样可以保证序列的执行性能 ;
@RestrictsSuspension
@SinceKotlin("1.3")
public abstract class SequenceScope<in T> internal constructor()
public abstract suspend fun yield(value: T)
public abstract suspend fun yieldAll(iterator: Iterator<T>)
public suspend fun yieldAll(elements: Iterable<T>)
if (elements is Collection && elements.isEmpty()) return
return yieldAll(elements.iterator())
public suspend fun yieldAll(sequence: Sequence<T>) = yieldAll(sequence.iterator())
向 sequence
方法中传入一个函数 , 该函数就会变成 SequenceScope
的扩展函数 , SequenceScope
类中的扩展函数是限制挂起的 , 只要是 SequenceScope
中 , 如果要调用挂起函数 , 只能调用其已有的挂起函数 , 如 : yield
, yieldAll
, 函数等 , 不能调用其它挂起函数 ;
RestrictsSuspension
注解的作用是 限制挂起 ;
/**
* 当用作扩展挂起函数的接收器时,标记有此注释的类和接口受到限制。
* 这些挂起扩展只能调用该特定接收器上的其他成员或扩展挂起函数,并且不能调用任意挂起函数。
*/
@SinceKotlin("1.3")
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
public annotation class RestrictsSuspension
四、协程中调用挂起函数返回集合
如果要 以异步方式 返回多个返回值 , 可以在协程中调用挂起函数返回集合 , 但是该方案只能一次性返回多个返回值 , 不能持续不断的 先后 返回 多个 返回值 ;
代码示例 :
package kim.hsl.coroutine
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
class MainActivity : AppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 携程中调用挂起函数返回多个值
// 调用 " 返回 List 集合的挂起函数 " , 并遍历返回值
runBlocking
listFunction().forEach
// 遍历打印集合中的内容
println(it)
/**
* 返回 List 集合的函数
*/
suspend fun listFunction(): List<Int>
delay(500)
return listOf(0, 1, 2)
执行结果 :
2022-12-22 13:37:00.191 26649-26649/kim.hsl.coroutine I/System.out: 0
2022-12-22 13:37:00.191 26649-26649/kim.hsl.coroutine I/System.out: 1
2022-12-22 13:37:00.191 26649-26649/kim.hsl.coroutine I/System.out: 2
以上是关于Kotlin 协程Flow 异步流 ① ( 以异步返回返回多个返回值 | 同步调用返回多个值的弊端 | 尝试在 sequence 中调用挂起函数返回多个返回值 | 协程中调用挂起函数返回集合 )的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin 协程Flow 异步流 ② ( 使用 Flow 异步流持续获取不同返回值 | Flow 异步流获取返回值方式与其它方式对比 | 在 Android 中使用 Flow 异步流下载文件 )
Kotlin 协程Flow 异步流 ② ( 使用 Flow 异步流持续获取不同返回值 | Flow 异步流获取返回值方式与其它方式对比 | 在 Android 中使用 Flow 异步流下载文件 )
Kotlin 协程Flow 异步流 ④ ( 流的构建器函数 | flow 构建器函数 | flowOf 构建器函数 | asFlow 构建器函数 )
Kotlin 协程Flow 异步流 ④ ( 流的构建器函数 | flow 构建器函数 | flowOf 构建器函数 | asFlow 构建器函数 )
Kotlin 协程Flow 异步流 ⑥ ( 调用 Flow#launchIn 函数指定流收集协程 | 通过取消流收集所在的协程取消流 )
Kotlin 协程Flow 异步流 ⑥ ( 调用 Flow#launchIn 函数指定流收集协程 | 通过取消流收集所在的协程取消流 )