【Kotlin回顾】25.Kotlin协程—select

Android安全存储利器Hawk:AES加密键值对存储库原理与实践 在Android应用开发中,数据持久化是基础且关键的技术环节,它确保了应用状态和用户数据的长期保存。其核心原理是通过本地存储机制,将内存中的数据结构序列化后写入设备存储介质。从技术价值看,安全高效的数据持久化能提升应用稳定性、保护用户隐私并优化用户体验。在移动开发领域,涉及用户凭证、应用配置等敏感信息的存储时,对安全性的要求尤为突出。传统的SharedPreferences虽然API简单,但以明文存储,存在安全风险;而直接使用SQLite数据库处理简单键值对又显得过于繁重。此时,专注于提供安全、轻量级键值对 阅读详情

select在1.6的版本中还是一个实验性的特性,但是如果select与Deferred、Channel结合使用的话可以显著的提高程序运行的效率以及改善程序的灵活性和可扩展性。今天主要来聊一聊select的使用。

1.select就是选择「更快」的结果

举个例子,现在要获取用户信息进行展示,有缓存获取和网络请求获取两种方式,正常情况下缓存获取是最快的但是信息不一定是最新的,网络获取比前者慢但是确实最新的,他们的代码逻辑可以这么写:

fun main() = runBlocking {

    val startTime = System.currentTimeMillis()

    val cacheUserInfo = getCacheUserInfo("张三")
    updateUI(cacheUserInfo)
    println("cache 耗时:${(System.currentTimeMillis() - startTime)}")

    val networkUserInfo = getNetworkUserInfo("李四")
    updateUI(networkUserInfo)
    println("network 耗时:${(System.currentTimeMillis() - startTime)}")

}

/**
 * 从缓存获取用户信息
 */
suspend fun getCacheUserInfo(name: String): User {
    delay(1000)
    return User(name, 20)
}

/**
 * 从网络获取用户信息
 */
suspend fun getNetworkUserInfo(name: String): User {
    delay(1500)
    return User(name, 44)
}

fun updateUI(user: User) {
    println("${user.name}:${user.age}")
}

data class User(
    val name: String,
    val age: Int
)

//输出结果:
//张三:20
//cache 耗时:1011
//李四:44
//network 耗时:2515

上面代码流程是先从缓存中获取信息,再从网络连接中获取信息,主要分为四步:

  • 第一步:查询缓存信息;
  • 第二步:缓存服务返回信息,更新 UI;
  • 第三步:查询网络服务;
  • 第四步:网络服务返回信息,更新 UI。

但是上面这段代码是建立在缓存获取信息没有问题或者比网络请求快的前提下,假如说这里的缓存出现了超时的问题那么网络请求的函数是无法被执行的,因为getCacheUserInfo是一个挂起函数,它在没有被恢复的时候后面的函数是无法被执行的,这里假设缓存出现了超时情况,将getCacheUserInfo函数中的delay(1000)改为delay(2000),那输出的结果如下:

//输出结果
//张三:20
//cache 耗时:2005
//李四:44
//network 耗时:3511

看的出来networkUserInfo最终获取到的时间也会被延长,那么如果将getCacheUserInfo()和getNetworkUserInfo()两个函数的执行改为并行的话即使缓存出现问题用户信息也是可以正常获取的,只不过走的是网络请求:

fun main() = runBlocking {

    val startTime = System.currentTimeMillis()

    val cacheDeffered = async {
        val cacheUserInfo = getCacheUserInfo("张三")
        updateUI(cacheUserInfo)
        println("cache 耗时:${(System.currentTimeMillis() - startTime)}")
    }

    val networkDeffered = async {
        val networkUserInfo = getNetworkUserInfo("李四")
        updateUI(networkUserInfo)
        println("network 耗时:${(System.currentTimeMillis() - startTime)}")
    }
}

//输出结果:
//李四:44
//network 耗时:1595
//张三:20
//cache 耗时:2085

从结果看的出来并行之后不存在getNetworkUserInfo被阻塞的情况,那么如果我想要的是这两种方式谁最先返回就用谁的数据呢要怎么实现,这里就进入倒了今天的主体:select。

2.select和async

用select将上面async实现并行的代码进行改造:

fun main() = runBlocking {

    val startTime = System.currentTimeMillis()

    val userInfo = select<User> {
        async { getCacheUserInfo("张三") }
            .onAwait { it } //这里是重点
        async { getNetworkUserInfo("李四") }
            .onAwait { it } //这里是重点
    }

    if(userInfo!=null){
        updateUI(userInfo)
        println("select 耗时:${(System.currentTimeMillis() - startTime)}")
    }
}

这里首先使用 select 这个高阶函数包裹了两次查询的服务,同时传入了泛型参数 User,代表我们要选择的数据类型是 User,然后在async后面添加了onAwait { it },这里的目的是为了将结果传递给select,select才能将结果返回给变量并在后面更新UI。

至于它的输出结果其实就是根据谁先有响应就输出谁的结果,比如说缓存获取时间为delay(1000)网络请求时间为delay(1500)得到的结果就是缓存的响应, 反过来的话得到的结果就是网络请求的响应, 所以select的作用就是选择最快有响应的哪一个结果进行输出, 这样就避免了等待太长的时间,得到糟糕的体验。

这里还存在一个问题,就是如果缓存获取不出现问题,那么缓存的获取是一定会比网络请求快的,用了select之后每次获取到的信息都是旧的了,这里要怎么解决?解决这个问题其实就是加一个标识,这里我贴上完整代码:

/**
 * 从缓存获取用户信息
 */
suspend fun getCacheUserInfo(name: String): User {
    delay(1000)
    return User(name, 20)
}

/**
 * 从网络获取用户信息
 */
suspend fun getNetworkUserInfo(name: String): User {
    delay(1500)
    return User(name, 44)
}

fun updateUI(user: User) {
    println("${user.name}:${user.age}")
}

data class User(
    val name: String,
    val age: Int,
    val isCache: Boolean = false
)

fun main() = runBlocking {
    val startTime = System.currentTimeMillis()

    val cacheUserInfo = async { getCacheUserInfo("张三") }
    val networkUserInfo = async { getNetworkUserInfo("李四") }

    val userInfo = select<User> {
        cacheUserInfo.onAwait { it?.copy(isCache = true) }
        networkUserInfo.onAwait { it?.copy(isCache = false) }
    }

    if (userInfo != null) {
        updateUI(userInfo)
        println("select 耗时:${(System.currentTimeMillis() - startTime)}")
    }

    if (userInfo != null && userInfo.isCache) {
        val network = networkUserInfo.await()?: return@runBlocking
        updateUI(network)
        println("network 耗时: ${System.currentTimeMillis() - startTime}")
    }
}

//输出结果
//张三:20
//select 耗时:1057
//李四:44
//network 耗时: 1571

通过isCache这个标识,当获取的是缓存数据时要再进行网络数据的请求,这样缓存中的数据就是重视最新的了。

3.select和channel

前面在channel使用篇讲过,channel可以发送多条数据,假设这里有这样一个需求,后台下发一个任务,每执行一步都要先在屏幕上展示,再写入本地文件(这两件事可以做成一件,这里主要为了举例),只用channel来实现的话大概是这样:

fun main() = runBlocking {
    val startTime = System.currentTimeMillis()

    val channelUI = produce {
        send("UI展示:任务启动")
        delay(100)
        send("UI展示:任务执行")
        delay(100)
        send("UI展示:任务终止")
        delay(100)
    }

    val channelFile = produce {
        send("写入文件:任务启动")
        delay(100)
        send("写入文件:任务执行")
        delay(100)
        send("写入文件:任务终止")
        delay(100)
    }

    channelUI.consumeEach{
        println(it)
    }

    channelFile.consumeEach{
        println(it)
    }

    println("耗时: ${System.currentTimeMillis() - startTime}")
}

//输出结果
//UI展示:任务启动
//UI展示:任务执行
//UI展示:任务终止
//写入文件:任务启动
//写入文件:任务执行
//写入文件:任务终止
//耗时: 686

从输出结果可以看到好像是实现这个需求,但是写入文件的操作是在UI展示完成后才开始执行,那么加入UI展示有很多呢?是不是就意味着写入文件这一操作什么时候执行也不知道了。

如果用select实现会是怎么样的结果呢:

fun main() = runBlocking {
    val startTime = System.currentTimeMillis()

    val channelUI = produce {
        send("UI展示:任务启动")
        delay(100)
        send("UI展示:任务执行")
        delay(100)
        send("UI展示:任务终止")
        delay(100)
    }

    val channelFile = produce {
        send("写入文件:任务启动")
        delay(100)
        send("写入文件:任务执行")
        delay(100)
        send("写入文件:任务终止")
        delay(100)
    }

    //1
    repeat(6) {
        selectChannel(channelUI, channelFile)
    }

    println("耗时: ${System.currentTimeMillis() - startTime}")
}

suspend fun selectChannel(
    channelUI: ReceiveChannel<String>, 
    channelFile: ReceiveChannel<String>
):String = select<String>{
    //2
    channelUI.onReceive{ it.also { println(it) } }
    channelFile.onReceive{ it.also { println(it) } }
}

//输出结果
//UI展示:任务启动
//写入文件:任务启动
//UI展示:任务执行
//写入文件:任务执行
//UI展示:任务终止
//写入文件:任务终止
//耗时: 400

先对上面的几个注释进行说明:

  • 注释1:执行6次,链各个管道中各有3条数据,执行6次的主要目的是将管道中的数据全部消耗掉;
  • 注释2:onReceive{} 是 Channel 在 select 当中的语法,当 Channel 当中有数据以后,它就会被回调,通过这个 Lambda,我们也可以将结果传出去

前后两种方式的执行结果对比可以发现,select的实现比Channel的实现耗费的时间更少,并且他们是交替执行的。那么此时如果channelUI遇到问题了channelFile是否会执行呢?

fun main() = runBlocking {
    val startTime = System.currentTimeMillis()

    val channelUI = produce<String> {
        delay(100000)
    }

    val channelFile = produce {
        send("写入文件:任务启动")
        delay(100)
        send("写入文件:任务执行")
        delay(100)
        send("写入文件:任务终止")
        delay(100)
    }

    repeat(6) {
        selectChannel(channelUI, channelFile)
    }

    println("耗时: ${System.currentTimeMillis() - startTime}")
}

suspend fun selectChannel(channelUI: ReceiveChannel<String>, channelFile: ReceiveChannel<String>):String = select<String>{
    channelUI.onReceive{ it.also { println(it) } }
    channelFile.onReceive{ it.also { println(it) } }
}

//输出结果
//写入文件:任务启动
//写入文件:任务执行
//写入文件:任务终止

//Exception in thread "main" kotlinx.coroutines.channels.ClosedReceiveChannelException: Channel was closed

可以看到这里正常的输出了channelFile的数据,这说明select加入后即使另一个管道没有数据也不会影响整个任务的执行。

在输出结果的同时还爆出了一个错误,这个错误的原因是,channel中只有三个数据,当他们发送完毕后就被关闭了,而第4次调用时因为channel已经被关闭了所以爆出了这个错误,如果把【6】改成【3】这个错误就不会出现了。但是在这个需求中并不知道具体有多少数据,那要解决这个问题就要使用onReceiveCatching{}了。

fun main() = runBlocking {
    val startTime = System.currentTimeMillis()

    val channelUI = produce<String> {
        delay(100000)
    }

    val channelFile = produce {
        send("写入文件:任务启动")
        delay(100)
        send("写入文件:任务执行")
        delay(100)
        send("写入文件:任务终止")
        delay(100)
    }

    repeat(6) {
        val result = selectChannel(channelUI, channelFile)
    	//打印结果
        println(result)
    }

    println("耗时: ${System.currentTimeMillis() - startTime}")
}

suspend fun selectChannel(channelUI: ReceiveChannel<String>, channelFile: ReceiveChannel<String>):String = select<String>{
    //这里做了改动
    channelUI.onReceiveCatching{ it.getOrNull() ?: "channelUI is closed!" }
    channelFile.onReceiveCatching{it.getOrNull() ?: "channelFile is closed!"  }
}

//输出结果
//写入文件:任务启动
//写入文件:任务执行
//写入文件:任务终止
//channelFile is closed!
//channelFile is closed!
//channelFile is closed!
//耗时: 442

这时候,即使不知道管道里有多少个数据,我们也不用担心崩溃的问题了。在 onReceiveCatching{} 这个高阶函数当中,我们可以使用 it.getOrNull() 来获取管道里的数据,如果获取的结果是 null,就代表管道已经被关闭了。不过,上面的代码仍然还有一个问题,那就是,得到所有结果以后,程序不会立即退出,因为我们的 channelUI 一直在 delay()。这时候,完成 6 次repeat()调用以后,将 channelUI、channelFile 取消即可。

//在repeat()后添加即可
channelUI.cancel() 
channelFile.cancel()

4.select和channel、Deffered之间的联系

通过前面的分析可以发现,当select加入后,它们原本的 API 会多一个 on 前缀。

所以,只要记住了 Deferred、Channel 的 API,你是不需要额外记忆 select 的 API 的,只需要在原本的 API 的前面加上一个 on 就行了。另外还要注意的是,当 select 与 Deferred 结合使用的时候,当并行的 Deferred 比较多的时候,你往往需要在得到一个最快的结果以后,去取消其他的 Deferred。

比如说,对于 Deferred1、Deferred2、Deferred3、Deferred4、Deferred5,其中 Deferred2 返回的结果最快,这时候,我们往往会希望取消其他的 Deferred,以节省资源。那么在这个时候,我们可以使用类似这样的方式:

fun main() = runBlocking {
    suspend fun <T> fastest(vararg deferreds: Deferred<T>): T = select {
        fun cancelAll() = deferreds.forEach { it.cancel() }

        for (deferred in deferreds) {
            deferred.onAwait {
                cancelAll()
                it
            }
        }
    }

    val deferred1 = async {
        delay(100L)
        println("done1")    // 没机会执行
        "result1"
    }

    val deferred2 = async {
        delay(50L)
        println("done2")
        "result2"
    }

    val deferred3 = async {
        delay(10000L)
        println("done3")    // 没机会执行
        "result3"
    }

    val deferred4 = async {
        delay(2000L)
        println("done4")    // 没机会执行
        "result4"
    }

    val deferred5 = async {
        delay(14000L)
        println("done5")    // 没机会执行
        "result5"
    }

    val result = fastest(deferred1, deferred2, deferred3, deferred4, deferred5)
    println(result)
}

/*
输出结果
done2
result2
*/

5.总结

  • select,就是选择“更快的结果”。
  • 当 select 与 async、Channel 搭配以后,可以并发执行协程任务,以此大大提升程序的执行效率甚至用户体验,并且还可以改善程序的扩展性、灵活性。
  • 关于 select 的 API,不需要去刻意记忆,只需要在 Deferred、Channel 的 API 基础上加上 on 这个前缀即可。

作者:无糖可乐爱好者
链接:https://juejin.cn/post/7181792189532831801

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集
在这里插入图片描述
二、源码解析合集

在这里插入图片描述
三、开源框架合集

在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接点击文末优快云官方认证微信卡片免费领取↓↓↓

SonarQube问题修复实战:从Bug、漏洞到代码异味的系统化解决方案 静态代码分析是现代软件工程保障代码质量与安全的核心实践。其原理是通过预定义规则集对源代码进行自动化扫描,识别潜在缺陷、安全漏洞和不良模式。这项技术的核心价值在于将质量保障左移,在开发阶段早期发现问题,显著降低后期修复成本并提升软件可维护性。在持续集成、DevOps等工程实践中,静态分析已成为构建健壮交付流水线的关键环节。本文聚焦于静态分析工具SonarQube的实战应用,针对其报告中的Bug、安全漏洞和代码异味三大类问题,提供从原理剖析到具体修复的完整指南。文章深入解析了空指针解引用、SQL注入、XSS攻击 阅读详情

相关推荐

Android:Google三方库之Adjust集成详细步骤

Android为APP添加google adjust功能

学习就是我的个性 4473

Kotlin协程-select基础

select——>用于选择更快的结果。基于场景理解比如客户端要查询一个商品的详情。两个服务:缓存服务,速度快但信息可能是旧的;网络服务,速度慢但信息一定是最新的。上述程序分为四步:第一步:查询缓存信息;第二步:缓存服务返回信息,更新 UI;第三步:查询网络服务;第四步:网络服务返回信息,更新 UI。用户可以第一时间看到商品的信息,虽然它暂时会展示旧的信息,但由于我们同时查询了网络服务,旧缓存信息也马上会被替代成新的信息。但是可能存在一些问题:如果程序卡在了缓存服务,获取网络服务就会无法执行。

且听真言 1384

IP白名单校验

支持格式: 1、127.0.0.1 // 指定固定IP 2、127.0.0.1-127.0.0.128 // 可使用“-”来表示一个IP区间,支持跨IP段(一般不会出现这种情况,跨IP段则配置多个规则) 3、127.0.* // 2~4位IP段可...

2199

【Kotlin】select简介

协程的 select 是一种用于异步操作的选择器,它允许同时等待多个挂起函数的结果,并在其中一个完成时执行相应的操作。能够被 select 的事件都是 SelectClause,在 select.kt 中有定义,如下。

little_fat_sheep 1365

Altium Designer许可证冲突?手把手教你用Windows防火墙彻底禁止AD联网(附详细截图)

本文详细介绍了如何通过Windows防火墙精准管控Altium Designer的网络权限,解决许可证冲突问题。通过配置入站和出站规则,彻底阻断AD的联网行为,提升软件运行效率。适用于需要稳定使用Altium Designer的工程师,附有详细截图和高级验证方法。

weixin_38170137的博客 423

保姆级避坑指南:用Docker在Ubuntu 22.04上部署Isaac Sim 5.1.0,搞定宇树G1仿真环境

本文提供了一份详细的保姆级避坑指南,帮助用户在Ubuntu 22.04上通过Docker部署Isaac Sim 5.1.0,并成功搭建宇树G1仿真环境。文章涵盖了环境准备、Docker与NVIDIA容器工具包的配置、Isaac Sim镜像的定制化拉取与配置,以及宇树G1仿真环境的实战调试,旨在帮助开发者高效解决部署过程中的常见问题。

weixin_33728268的博客 205

Kotlin 协程 Select:看我如何多路复用

协程通信三剑客:Channel、Select、Flow,上篇已经分析了Channel的深水区,本篇将会重点分析Select的使用及原理。

1238

C#与发那科机器人通信实战:从SDK配置到机械臂控制

本文详细介绍了如何使用C#与发那科机器人进行通信,从SDK配置到机械臂控制的完整实战流程。内容包括环境准备、通信连接建立、机械臂运动控制、异常处理与状态监控,以及高级功能实战,帮助开发者快速掌握工业机器人编程技术。

weixin_42524276的博客 457

Kotlin select 选择最快结果

select是Kotlin 1.6中的特性,即选择最快的结果。 select与async、Channel结合使用,可以大大提高程序的响应速度,还可以提高程序的灵活性、扩展性。

xiangxiongfly 1691

R数据分析:广义估计方程式GEE的做法和解释

好久没有更新文章了,因为同学们咨询的问题有点多,另一个原因就是自己实在太懒。。。。 今天继续给大家写广义估计方程式GEE。 In statistics, a generalized estimating equation (GEE) is used to estimate the parameters of a generalized linear model with a possible unknown correlation between outcomes. 上面的英文解释告诉我们,当我们

Codewar的博客 1万+

【虚幻引擎UE】UE5 四步骤实现AI漫游与对话行为(含工程源码)

【虚幻引擎UE】UE5 四步骤实现AI漫游与对话行为(含工程源码)

灵境引路人 3227

Kotlin select使用方法介绍

select是Kotlin 1.6中的特性,即选择最快的结果。select与async、Channel结合使用,可以大大提高程序的响应速度,还可以提高程序的灵活性、扩展性。

chuyouyinghe的专栏 257

四旋翼飞行器建模(一)

四旋翼飞行器的姿态运动学和姿态动力学建模方法。

加斯顿工程师的博客 683

Android开发工程师核心技能与面试全攻略

移动应用开发中,Android系统凭借其70%以上的市场占有率占据主导地位。掌握Java/Kotlin语言基础、Android SDK核心组件及Jetpack架构组件是现代开发的必备技能。性能优化涉及内存管理、UI渲染和网络请求等关键技术,使用工具链如Android Profiler和LeakCanary可有效解决问题。在跨平台开发趋势下,Kotlin Multiplatform和Compose声明式UI成为热点。面试准备需涵盖算法、系统设计和项目经验阐述,职业发展可从技术深度或管理方向规划。

a359798678的博客 381

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

编程语言难度排名:从Python到汇编,如何选择最适合你的学习路径?

编程语言作为软件开发的基石,其学习难度直接影响开发者的入门效率和职业发展。不同语言的设计哲学、语法特性和应用场景决定了其学习曲线的陡峭程度。从语法亲和力、编程范式、生态工具链、调试成本和社区资源五个维度综合评估,可以构建一个务实的“难度测量仪”。例如,Python以其简洁语法和丰富库生态成为新手友好型语言,而JavaScript则因异步编程和快速迭代的框架生态增加了实践复杂度。对于追求高性能和系统级控制的开发者,C++和Rust提供了强大能力,但也带来了手动内存管理和所有权模型等高级概念的学习门槛。理解这些

weixin_30326741的博客 428

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

工作中使用到的单词(软件开发)

1.エイリアス   alias 别名 powershell使用 get-help 命令时,会得到与此命令 相关(别名)的命令 2.プロキシ proxy 代 理 3.プロモート   promote 促进,提升   开发的系统新功能上线发布,有时会使用到这个词,比如 STプロモート 还有使用リリース这个词的。比如STリリース。个人认为两者含义相同。 4.見逃し み................................................................

sun0322 6万+

基于HarmonyOS API 24实战解析电影收藏管理@ObjectLink 则用于子组件中接收一个 @Observed 对象的引用,使得子组件能够对该对象的属性变化做出响应式更新

在移动互联网与智能穿戴设备高度普及的今天,"习惯养成"已经从一个模糊的自我管理理念,演变为一个可量化、可追踪、可视化的数字化产品赛道。越来越多的人希望借助手中的智能终端,把"早起、冥想、阅读、运动"这些抽象的自律行为,转化为一条条清晰的数据曲线和一张张可触摸的打卡卡片。而鸿蒙生态(HarmonyOS)凭借其跨设备协同、分布式软总线以及声明式 UI 开发框架 ArkUI,为这类注重"轻量化交互 + 即时反馈"的生活方式类应用提供了极为理想的生长土壤。本应用正是一款面向"晨间场景"深度打磨的习惯追踪工具。它聚焦

2301_79516720的博客 163

HarmonyOS 6效果实现:bindSheet / bindContentCover 统一管理浮层高内聚低耦合的页面结构

在React Native中开发鸿组件(这里指的是鸿蒙(HarmonyOS)组件),你需要了解鸿蒙开发的基础以及如何在React Native项目中集成鸿蒙应用。鸿蒙OS是由华为开发的一个分布式操作系统,主要用于其智能设备,如手机、平板、智能手表等。首先,你需要熟悉鸿蒙OS的开发环境设置和基本开发流程。React Native本身主要用于Harmony和Harmony平台的开发,但你可以通过以下几种方式将鸿蒙应用集成到React Native项目中:A. 使用WebView。

qq63160596的博客 179

Kotlin 协程 - 多路复用 select()

多个方式获取数据,哪个更快返回结果就用哪个,同时到达会优先选择前一个观察的,想随机的话使用 selectUnbiased() 替换 select()。能被选择的都是 SelectClauseN 类型。

HugMua的博客 1624

Kotlin 协程的 select 特性及其应用

Deferred 是一种表示异步计算结果的对象,它可以通过 await 方法来获取结果,或者通过 isCompleted 属性来判断是否完成。如果有多个 Deferred 对象,我们可能想要获取最快的那个结果,或者优先显示缓存数据,再显示网络数据。这时,我们可以使用 select 来实现这样的逻辑。

大模型训练 303

Kotlin协程Select机制:多路复用的艺术

Select是Kotlin协程中一个强大的并发原语,它允许我们在多个挂起操作中选择最先完成的结果。实现高效竞速:在多个服务调用中选择最快的响应构建响应式系统:同时监听多个数据源实现服务降级:在主服务失败时快速切换到备用服务优化资源使用:避免不必要的等待时间关键要点Select通过注册选择子句和竞争机制实现多路复用底层依赖于协程的挂起/恢复机制和无锁数据结构适用于"第一个可用结果"场景,而非收集所有结果需要与结构化并发结合,确保资源正确清理。

2501_93078354的博客 940

Kotlin Coroutines包下的select函数简介

想象一下这个场景,在程序应用中,为了实现一个业务逻辑,你可能有好几种方式来实现,但是我只需要最快实现结果的一种方式,这时候我们就可以使用select函数了。如果还不是很清楚啥意思,我们可以看下图:最近黄金比较贵,我们的客户端需要实时查询黄金的价格,现在网易服务器和头条服务器都同时提供查询的接口,在同一时间节点上理论上网易服务器和头条服务器返回的数据应该是一样的,我此时同时向网易和头条服务器发送请求数据,那么我此时查询只需要最快返回结果即可。形象一点,我们可以理解为数据的军备竞赛。

成长的烧年 1010

Kotlin协程Select(十一)

文章目录一、前言二、select三、通道关闭时候的Select四、onSend五、延迟onAwait六、在延迟通道上切换七、参考链接 一、前言 select 表达式可以同时等待多个挂起函数,并 选择 第一个可用的。这样就可以实现这样一种功能,同时执行不同的处理,哪种返回了就处理哪种。 二、select 下面是一种简单的演示: fun CoroutineScope.fizz() = produce<String> { while (true) { // 每 300 毫秒发送一个 "Fizz

Mr_Tony的专栏 777

Kotlin——jetpackCompose按钮弹出dialog、列表(类似recyclerView)、双向绑定--列表(可单选/多选)、列表选中显示边框(最简单的方式)

package com.example.jetpackcompose import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose....

wy313622821的博客 7621

Android开发者快速上手Kotlin(八) 之 协程官方框架Channel、Select和Flow的使用

接《Android开发者快速上手Kotlin(七) 之 协程官方框架初步》文章继续。 14 协程官方框架Channel、Select和Flow 14.1 Channel Channel我们一般翻译成叫通道,用于多个协程之间进行数据相互传输,多个协程允许发送和接收同一个Channel的数据。它类似于线程任务队列BlockingQueue + 挂起函数的支持,因为如果通道支持缓存的话,那么它实质上就是一个队列。我们发消息和接收消息都是挂起函数,挂起取决于Channel的状态,如果Channel已经满了.

子云心的博客 2936

Kotlin系列之常用操作符

前言:本篇文章来介绍下Kotlin的常用操作符。kotlin相对于java来说是一门十分简洁的语言,这其中操作符起了很大的作用,这些操作符和Rxjava的十分类似,如果你十分熟悉Rxjava,那么这些操作符学起来就得心应手很多,毕竟这些操作符还是挺简单的说。。。常用操作符大致可以分为 总数操作符 过滤操作符 映射操作符 元素操作符 生产操作符 顺序操作符 首先我想说的是,学习这些操作符应该从以下几个

Young 5153
上一篇: 2023最新整理,Android车载操作系统开发揭秘,无偿分享!
下一篇: 2023最新Android进阶笔记,八大模块,从入门到精通
Agent学习路线
博客等级 码龄6年 1万+粉丝 1902原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值