0
点赞
收藏
分享

微信扫一扫

【Kotlin 协程】Flow 异步流 ① ( 以异步返回返回多个返回值 | 同步调用返回多个值的弊端 | 尝试在 sequence 中调用挂起函数返回多个返回值 | 协程中调用挂起函数返回集合 )


文章目录

  • ​​一、以异步返回返回多个返回值​​
  • ​​二、同步调用返回多个值的弊端​​
  • ​​三、尝试在 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

【Kotlin 协程】Flow 异步流 ① ( 以异步返回返回多个返回值 | 同步调用返回多个值的弊端 | 尝试在 sequence 中调用挂起函数返回多个返回值 | 协程中调用挂起函数返回集合 )_kotlin






三、尝试在 sequence 中调用挂起函数返回多个返回值


尝试使用 挂起函数 ​​kotlinx.coroutines.delay​​ 进行休眠 , 这样在挂起时 , 不影响主线程的其它操作 , 此时会报如下错误 ;

【Kotlin 协程】Flow 异步流 ① ( 以异步返回返回多个返回值 | 同步调用返回多个值的弊端 | 尝试在 sequence 中调用挂起函数返回多个返回值 | 协程中调用挂起函数返回集合 )_协程_02

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 中调用挂起函数返回多个返回值 | 协程中调用挂起函数返回集合 )_Flow_03


举报

相关推荐

0 条评论