前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Kotlin 协程】Flow 异步流 ① ( 以异步返回返回多个返回值 | 同步调用返回多个值的弊端 | 尝试在 sequence 中调用挂起函数返回多个返回值 | 协程中调用挂起函数返回集合 )

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

作者头像
韩曙亮
发布2023-03-30 18:28:39
8.2K0
发布2023-03-30 18:28:39
举报
文章被收录于专栏:韩曙亮的移动开发专栏

文章目录

一、以异步返回返回多个返回值


在 Kotlin 协程 Coroutine 中 , 使用 suspend 挂起函数 以异步的方式 返回单个返回值肯定可以实现 , 参考 【Kotlin 协程】协程的挂起和恢复 ① ( 协程的挂起和恢复概念 | 协程的 suspend 挂起函数 ) 博客 ;

如果要 以异步的方式 返回多个元素的返回值 , 可以使用如下方案 :

  • 集合
  • 序列
  • Suspend 挂起函数
  • Flow 异步流

二、同步调用返回多个值的弊端


同步调用返回集合和序列代码示例 : 同步调用函数时 , 如果函数耗时太长或者中途有休眠 , 则会阻塞主线程导致 ANR 异常 ;

代码语言:javascript
复制
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)
        }
    }
}

执行结果 :

代码语言:javascript
复制
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 进行休眠 , 这样在挂起时 , 不影响主线程的其它操作 , 此时会报如下错误 ;

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
Restricted suspending functions can only invoke member or extension suspending functions 
on their restricted coroutine scope

受限挂起函数只能在其受限的协程范围上调用成员或扩展挂起函数

下面分析上述报错原因 :

sequence 函数中 , 传入的是 @BuilderInference block: suspend SequenceScope<T>.() -> Unit 参数 , 该参数是一个函数 , 该函数 () -> UnitSequenceScope 类型的扩展函数 ;

任意传入一个匿名函数 , 该函数被自动设置为 SequenceScope 类的扩展函数 , 在其中的任何调用都默认调用的是 SequenceScope 对象的方法 ;

在该匿名函数中 , 不能调用 SequenceScope 之外定义的挂起函数 , 这样做是为了保证该类的执行性能 ;

代码语言:javascript
复制
/**
 * 构建一个[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 注解的作用是 限制挂起 , 在该类中不能调用其它的挂起函数 , 这样可以保证序列的执行性能 ;

代码语言:javascript
复制
@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 注解的作用是 限制挂起 ;

代码语言:javascript
复制
/**
 * 当用作扩展挂起函数的接收器时,标记有此注释的类和接口受到限制。
 * 这些挂起扩展只能调用该特定接收器上的其他成员或扩展挂起函数,并且不能调用任意挂起函数。
 */
@SinceKotlin("1.3")
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
public annotation class RestrictsSuspension

四、协程中调用挂起函数返回集合


如果要 以异步方式 返回多个返回值 , 可以在协程中调用挂起函数返回集合 , 但是该方案只能一次性返回多个返回值 , 不能持续不断的 先后 返回 多个 返回值 ;

代码示例 :

代码语言:javascript
复制
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)
    }
}

执行结果 :

代码语言:javascript
复制
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
在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-12-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 一、以异步返回返回多个返回值
  • 二、同步调用返回多个值的弊端
  • 三、尝试在 sequence 中调用挂起函数返回多个返回值
  • 四、协程中调用挂起函数返回集合
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档