Android笔记(十五):JetPack Compose的附带效应(二)-produceState和derivedStateOf

在本笔记中,将结合实例介绍produceState和derivedStateOf两个可组合函数。它们分别实现状态的转换。
(1)produceState将非Compose状态转换虫Compose状态
(2)derivedStateOf将多个状态转换成其他状态。

一、produceState

produceState可将非 Compose 状态转换为 Compose 状态,它会在没有定义数据源的情况下随时间生成值。produceState 会启动一个协程,该协程将作用域限定为可将值推送到返回的 State 的组合。

produceState可组合函数返回一个可观察的快照状态,当produceState函数进入组合会启动producer的操作,创建一个状态值。如果key1和key2的值发生了变化,正在运行的producer会被取消并重新加载创建新的状态源。producer使用ProducerStateScope.value为返回的状态设置新的值:

如果ProducerStateScope.value混淆了返回状态的新旧值,使得ProducerStateScope.value返回的状态的值仍为状态旧值,则不会观察到任何的更改。
如果在频繁设置多个新值,那么观察者只会观察到最新的值。

在下列中访问并显示网络中的在线图片,因为网络请求到缓存到本地存在时间差,因此考虑将这样的处理使用produceState来完成。只要状态值更新,就刷新界面。
(1)定义请求结果的类
请求资源结果的类OpResult是密封类,封装了两种处理方式:请求图片资源成功和请求图片资源失败两种子类。

sealed class OpResult<T>(){
    object Loading:OpResult<ImageBitmap>()
    object Error:OpResult<ImageBitmap>()
    data class Success(val image:ImageBitmap):OpResult<ImageBitmap>()
}

(2)定义图片库ImageRepository

class ImageRepository  constructor(context:Context){
    val context:Context = context
    var id = 0
    //https://wome.com网站不存在,网站的图片链接均为假,调试时请自行设置
    val imageLst =listOf("https://some.com.1.jpg",
            "https://some.com.2.jpg",
            "https://some.com.3.jpg",
            "https://some.com.4.jpg")
    fun findByUrl(url:String) =  imageLst.indexOf(url)
    //请求下一个图片资源的url字符串 
    suspend fun next():String{
        id = (id+1)%imageLst.size
        return imageLst.get(id)
    }

	//请求上一个图片资源的url字符串 
    suspend fun prev():String{
        id = (id-1+imageLst.size)%imageLst.size
        return imageLst.get(id)
    }
    
    /加载在线图片资源,返回ImageBitmap
    suspend fun loadImageByUrl(url:String): ImageBitmap {
        //请求在线图片
        val request = ImageRequest.Builder(context).data(url).build()
        val imageLoader by lazy{ ImageLoader(context) }
        return (imageLoader.execute(request).drawable as BitmapDrawable)
               .bitmap.asImageBitmap().apply{
                //延迟两秒加载图片
                delay(1000)
            }
    }
}

因为要访问网络在线图片。因此,需要在应用的AndroidManifest.xml中设置网络访问权限:

<uses-permission android:name="android.permission.INTERNET" />

在上述请求网络在线的图片资源,需要coil库,因此在项目模块的build.gradle.kt中设置为:

implementation(“io.coil-kt:coil-compose:2.4.0”)

(3)定义可组合函数请求在线图片

/**
 * 将非Composable状态转换成Composable状态
 * @param imageRepository ImageRepository 图片仓库
 * @return State<OpResult<ImageBitmap>>
 */
@Composable
fun loadNetworkImages(imageRepository: ImageRepository):State<OpResult<ImageBitmap>>{
    return produceState<OpResult<ImageBitmap>>(initialValue = OpResult.Loading){
                            for(i in 0 until imageRepository.imageLst.size) {
                                var image = imageRepository.loadImageByUrl(imageRepository.imageLst[i])
                                value = if (image == null) {
                                    OpResult.Error
                                } else {
                                    OpResult.Success(image)
                                }
                            }
    }
}

在此处,返回一个包含请求资源结果的状态,根据循环,使得图片列表的索引值发生变换,从图片仓库对象imageRepository中要加载的图片。如果图片请求成功,将image图片封装到状态的值为OpResult.Success(image)中。

(4)定义界面ImageScreen

@Composable
fun ImageScreen(imageRepository: ImageRepository) {
    val result by  loadNetworkImages(imageRepository = imageRepository) //从图片仓库中请求资源,返回包含请求结果的状态
    Box(
        modifier = Modifier.fillMaxSize().background(Color.Black),
        contentAlignment = Alignment.Center
    ) {
        Column(
            modifier = Modifier.fillMaxWidth().height(300.dp),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            when(result) {
                is OpResult.Success -> {
                    Image(modifier = Modifier.size(400.dp,300.dp),
                        bitmap = (result as OpResult.Success).image,
                        contentDescription = null
                    )
                }
                is OpResult.Error -> {
                    Image(
                        imageVector = Icons.Filled.Warning,
                        contentDescription = null,
                        modifier = Modifier.size(200.dp, 200.dp)
                    )
                }
                else -> {//等待加载图片时,显示圆形进度条
                    CircularProgressIndicator()
                }
            }
        }
    }
}

(5)定义主活动MainActivity

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val imageRepository = ImageRepository(this)
        setContent {
            Ch06_DemoTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    ImageScreen(imageRepository)
                }
            }
        }
    }
}

运行结果就是图片动态显示直至最后一张图片为止,如下图所示:
在这里插入图片描述
模拟器中图片资源来自于网络。如有侵权,会主动删除。

二、derivedStateOf

derivedStateOf函数将一个或多个状态对象转换为其他状态,使用此函数可确保仅当计算中使用的状态之一发生变化时才会进行计算。首先,从一个简单的例子来初步了解:

@Composable
fun DisplayScreen(){
    val yearState = remember{mutableStateOf(2023)}
    val monthState = remember{mutableStateOf(11)}

    val calendarState = remember {
        derivedStateOf {
            "${yearState.value}年-${monthState.value}月"
        }
    }

    Box(contentAlignment = Alignment.Center){
        Column(modifier = Modifier.fillMaxWidth(),
            horizontalAlignment = Alignment.CenterHorizontally){
            Text("${calendarState.value}",fontSize=30.sp)
            Button(onClick ={
                monthState.value = (monthState.value)%12
                if(monthState.value == 0 ){
                    yearState.value++
                }
                monthState.value++
            }){
                Text("修改月份",fontSize = 24.sp)
            }
        }

    }
}

在上述的代码中,定义了两个状态值分别为yearState和monthState,通过derivedStateOf函数将两个状态的值连接生成一个新的状态CalendarState,而这个CalendarState的值为字符串。通过点击按钮,修改monthState和yearState的值,在界面中显示的CalendarState的值也发生相应的变化。

参考文献

Compose 中的附带效应
https://developer.android.google.cn/jetpack/compose/side-effects?hl=zh-cn

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/184427.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

NFC技术简介

NFC简介 NFC(近场通信&#xff0c;Near Field Communication&#xff09;是一种短距高频的无线电技术&#xff0c;由非接触式射频识别(RFID)演变而来。 NFC工作频率为13.56Hz&#xff0c;通常只有在距离不超过4厘米时才能启动连接&#xff0c;其传输速度有106 Kbit/秒、212 Kb…

「Whale 帷幄」连续入选科技榜单,AGI 冲击波正在加速行业洗牌

以 AGI 为底座&#xff0c;品牌 MarTech 正在经历一场前所未有的深度变革。 近日&#xff0c;弯弓研究院发布「中国 MarTech 500 强榜单」&#xff0c;以 2023 中国营销技术&#xff08;MarTech&#xff09;生态为研究对象&#xff0c;洞察行业现象与未来趋势。作为品牌数字化…

视频剪辑新招:批量随机分割,分享精彩瞬间

随着社交媒体的普及&#xff0c;短视频已经成为分享生活、交流信息的重要方式。为制作出吸引的短视频&#xff0c;许多创作者都投入了大量的时间和精力进行剪辑。然而&#xff0c;对于一些没有剪辑经验的新手来说&#xff0c;这个过程可能会非常繁琐。现在一起来看云炫AI智剪批…

AI制作的《大多数普通女孩的一生》——公开教程和工作流

内容来源&#xff1a;JiamigouCn ​这周由AI制作的《大多数普通女孩的一生》&#xff0c;在抖音爆火&#xff0c;获得新华网转发。到目前为止&#xff0c;全网还没有公开教程和工作流&#xff0c;需要花费800-2000购买。 本着AI社区共享原则&#xff0c;我委托公众号“楚思智能…

Debian12试用报告

环境: win11vbox 虚拟机 网络: host-only访问局域网 nat 访问外网, 配置为dhcp动态获取ip 遇到的问题: 偶尔卡死: nat每次开机都不生效, 外网无法访问; 开机后 重启网络可解决 sudo /etc/init.d/networking restart host-only倒是没问题, 内网正常访问 vim9还是用不习…

ubuntu22.04 arrch64版在线安装java环境

脚本 #安装java#!/bin/bashif type -p java; thenecho "Java has been installed."else#2.Installed Java , must install wgetwget -c https://repo.huaweicloud.com/java/jdk/8u151-b12/jdk-8u151-linux-arm64-vfp-hflt.tar.gz;tar -zxvf ./jdk-8u151-linux-arm6…

【Spring集成MyBatis】核心配置文件

文章目录 1. typeHandlers标签2. plugins标签通过PageHelper的API获取分页的信息 1. typeHandlers标签 可以重写类型处理器&#xff0c;或创建类型处理器来处理不支持/非标准的类型。选择性地将它映射到一个JDBC类型&#xff1a;如Java中的Date类型&#xff0c;将其存放到数据…

“土味出海”,屡试不爽!短剧出海引来新一轮爆发?

土味和“钱途”并存的短剧不仅在国内迅猛爆发&#xff0c;今年下半年以来海外市场多部爆火短剧出现&#xff0c;“短剧出海”的话题热度不断攀升&#xff0c;丝毫不差2021年网文出海的盛况。 “霸总的爱&#xff0c;日入千万刀”&#xff0c;是真实存在的&#xff01; 据统计…

快手ConnectionError

因为运行的程序被中断导致 top然后查看站用处内存高的accelerate kill进程号 9回车

概要设计文档案例分享

1引言 1.1编写目的 1.2项目背景 1.3参考资料 2系统总体设计 2.1整体架构 2.2整体功能架构 2.3整体技术架构 2.4运行环境设计 2.5设计目标 3系统功能模块设计 3.1个人办公 4性能设计 4.1响应时间 4.2并发用户数 5接口设计 5.1接口设计原则 5.2接口实现方式 6运行设计 6.1运行模块…

图像标记上线,描点信息尽在掌握丨三叠云

图像标记 路径 表单设计 >> 组件 >> 增强组件 功能简介 「图像标记」字段是「增强字段」类型字段。用户通过上传图片的方式构建一个背景图片&#xff0c;并在构建的图片背景上添加描点信息。搭配「仪表盘」中的「图像轨迹」&#xff0c;可绘制出相应的数据轨迹…

MySQL数据库入门到大牛_基础_14_视图及基本操作

本章开始将会介绍表之外的数据库对象。 文章目录 1. 常见的数据库对象2. 视图概述2.1 为什么使用视图&#xff1f;2.2 视图的理解 3. 创建视图3.1 创建单表视图3.2 创建多表联合视图3.3 基于视图创建视图 4. 查看视图5. 更新视图的数据5.1 一般情况5.2 不可更新的视图 6. 修改…

马斯克星链与芯事:30亿美元炸出卫星互联网革命,GPU算力创无限可能

★卫星互联网&#xff1b;算力&#xff1b;卫星通信&#xff1b;互联网&#xff1b;低轨卫星互联网&#xff1b;5G基础设施&#xff1b;GPT-4 Turbo&#xff1b;算力&#xff1b;地面通信&#xff1b;液冷&#xff1b;水冷&#xff1b;AI服务器&#xff1b;东数西算&#xff1b…

收藏这几个开源库,写css你会笑出声

你是否遇到过写css没灵感&#xff0c;写不出酷炫的效果&#xff0c;那这篇文章你一定要看完。知道这几个开源库&#xff0c;它能让你写出炸天的效果并且有效地增加你的摸鱼时长。 1.CSS Inspiration 网址&#xff1a;https://chokcoco.github.io/CSS-Inspiration/#/ CSS Insp…

时间序列分析算法的概念、模型检验及应用

时间序列分析是一种用于研究随时间变化的数据模式和趋势的统计方法。这类数据通常按照时间顺序排列&#xff0c;例如股票价格、气温、销售额等。时间序列分析的目标是从过去的观测中提取信息&#xff0c;以便预测未来的趋势。 以下是关于时间序列分析的一些重要概念、模型检验…

[Android]使用Retrofit进行网络请求

以下是使用 Retrofit 发送 POST 请求获取分页城市列表的 Kotlin 代码示例 1.在你的 build.gradle 文件中添加 Retrofit 和 Gson 的依赖 dependencies {......implementation("com.squareup.retrofit2:retrofit:2.9.0")implementation("com.squareup.retrofit2…

在Linux服务器部署爬虫程序?大佬只需七步!

之前在某乎上看见一篇关于《为什么很多程序员都建议使用 Linux》的文章&#xff0c;结合我自身关于Linux的使用经验。心血来潮得写了一段关于我在Linux系统部署爬虫程序的心得&#xff0c;希望结识更多的爬虫技术大佬&#xff0c;一起游弋在代码世界中。 根据我多年在Linux上部…

基于C#实现Dijkstra算法

或许在生活中&#xff0c;经常会碰到针对某一个问题&#xff0c;在众多的限制条件下&#xff0c;如何去寻找一个最优解&#xff1f;可能大家想到了很多诸如“线性规划”&#xff0c;“动态规划”这些经典策略&#xff0c;当然有的问题我们可以用贪心来寻求整体最优解&#xff0…

vue3.0使用leaflet

1、获取天地图密钥; 访问:https://www.tianditu.gov.cn/ 注册并登录,访问开发资源 =》地图API =》 地图服务=》申请key 应用管理=》创建新应用=》获取到对应天地图key 2、引入leaflet组件 参考资料:https://leafletjs.com/reference.html#path npm install leaflet …

用自己热爱的事赚钱,是多么的幸福

挖掘天赋可能有些困难&#xff0c;但挖掘爱好就简单多啦&#xff01;最幸福的事情就是能用自己喜欢的事情赚钱。 我们要说的是一个博主&#xff0c;他非常喜欢骑自行车&#xff0c;虽然他的工作是在外贸公司做销售&#xff0c;但每当有空时&#xff0c;他都会骑自行车。而且他…