Jetpack Compose - 通过State理解与管理你的UI

由于 Compose 是声明式工具集,因此更新它的唯一方法是通过新参数调用同一可组合项。这些参数是界面状态的表现形式。每当状态更新时,都会发生重组。

本篇文章将从导图中五方面分别介绍State的相关概念和用法

简介

Compose是一种新式声明性界面工具包,它和我们之前一直接触的View体系完全不同,比如之前我们想更新TextView显示文字,可以直接使用TextView.setText()来改变界面上显示的文案,而在Compose中,已经不支持这种更新方式,取而代之的是更新这个可组合项引用的State值,这样就会触发可组合项的重组事件,重组之后可组合项会获取到State最新的值并显示在界面上,下方图片就是Compose中可组合项的生命周期:进入组合 -> 执行0次或多次重组 -> 最后是退出组合。

Compose中采用的是State来作用于可组合项中值的读取和更改,在值更改(与更改前值不同)之后就会触发可组合项的重组,从而达到界面刷新的机制。

remember{}

remember{}可以将对象存储在内存当中,在第一次组合的时候将从remember提供的值存储到组合项中,并在重组期间返回最新存储的值。

上面我们使用remember{ mutableStateOf("init") }创建了一个可变的State,然后在按钮点击之后改变它的值,最终会在Text中呈现出来,这里需要注意的一点就是通过= remember{}这种方式创建的结果是state对象,在引用或者修改其值时需要调用state.value,下面还有介绍两种不同的方式来创建state,原理都是一致只是返回的对象不同而已。

接着我们再来看看另外两种方式是如何使用state

  • by remember{}通过委托方式进行创建state,此方式返回的对象为state的泛型值
  • (value, changeValue) = remember{}通过解构方式进行创建state,此方式第一个参数为返回的具体值,第二个参数为Lambda表达式,可直接修改状态值

这里也有一点需要大家注意,就是第二种委托方式创建的对象如果需要进行修改,就得使用var来修饰,并且需要额外导入两个包androidx.compose.runtime.getValueandroidx.compose.runtime.setValue,否则AS会一直爆红提示。

通过上面的代码示例想必大家都已经了解了如何去使用remember{}方式去创建和使用state,到这为止大家不妨将手机屏幕旋转一下,看看更新后的state值是什么样,在小节开头的时候提到,remember{}方式是将值存到内存当中,它并不能在配置更改后依然保存最新的值,而是会恢复成初始值,如果遇到这种情况,大家就需要使用另外一种,那就是rememberSaveable{}它会将值保存到Bundle中,即使在屏幕旋转等配置更改之后也会取到最新的值,并不会丢失。具体用法这里就不再多做演示,大家可以自行体验一下。

LiveData.obseverAsState()

LiveData我们接触的比较早了,之前也写过一篇文章简单介绍了它的使用和源码,它是一种可观察的数据存储器类,通常结合ViewModel 使用,下面我们就通过代码来看下在Compose种如何使用它来转换成State

使用LiveData.observeAsState()前需要添加额外的依赖:androidx.compose.runtime:runtime-livedata:1.4.3,它可以之前将LiveData转换成State,这样我们在引用LiveData值的时候就可以直接引用State的值了,修改值依然可以直接修改LiveData的值,Compose会自动响应修改的变化。

其内部实现也是非常简单,采用DisposableEffect副作用机制,内部添加LiveData的观察者,将观察到的值赋予state,然后在onDispose{}种取消观察者,通过源码可以看出,这里是绑定了生命周期的,在onDestroy()时会触发onDispose{},所以在使用这种方式的情况下,大家不必担心会产生内存泄露问题,内部已经帮我们处理过了,下面是源码大家可以自行消化下。

Flow.collectAsState()

Flow是Kotlin种一种数据流模型,它的原理就类似水流管道,上游发射下游接收,关于Flow也是写过两片文章分别介绍了基本的使用操作符大全,如果还没有接触过的小伙伴可以先看下前面两片文章,熟悉下如何简单使用,下面我们直接来看下在Compose种如何使用Flow

图片代码中我们采用的是collectAsState()Flow转换成State对象,读取其值是和LiveData一样,直接读取State的值,修改值时直接更新Flow的值。

这里的collectAsState()不推荐大家使用,因为它没有绑定生命周期,它内部是直接collect{}收集流的值,然后转换成State对象,并没有考虑到生命周期的问题,官方提供了另外一种方式帮助我们将Flow转换成State,也就是collectAsStateWithLifecycle(),这种方式采用了lifecycle.repeatOnLifecycle(){}来绑定生命周期,并且我们可以自定义在哪一时刻开始收集数据。

此方法有四个参数:

  • initalValue可以定义初始值
  • lifecycle用于管理生命周期,在Compose种可以通过LocalLifecycleOwner.current获取到当前的生命周期管理者
  • minActiveState此参数就是定义最小在哪个周期开始收集流的值
  • context这个就是协程的上下文,用于启动协程,默认为EmptyCoroutineContext

内部采用的是produceState()方式,这里具体用法会在文章接下来详细介绍,它就是将我们所需要的观察状态转换成State对象,这样就可以供Compose响应此状态。

produceState

produceState是Compose提供的一种创建State的方式,它可以帮助我们自由的生成State对象

这是最简单的一种方式,只有两个参数:

  • initialValue提供一个初始值
  • producer()它是一个挂起函数,我们可以在其内部使用协程并且提供State的值

下面我们通过此方式来模拟一个定时器的实现,倒计时60s,每秒更新下Text文字

实现过程也是非常的简单,在producer中通过协程的delay模拟延时1s的效果,然后通过this.value来更新State的值。具体效果见下方GIF

到这4种方式就介绍完了,除了produceState之外其它的三种基本上和我们项目的选型相关,如果项目已经采用了Kotlin的协程,那我们可以直接采用Flow的方式,目前已经完善的挺全面了,而且操作符也是应有尽有,大家可以按需选择~

关于我

我是Taonce,如果觉得本文对你有所帮助,帮忙关注、赞或者收藏三连一下,谢谢~

相关推荐
儿歌八万首1 小时前
Jetpack Compose 实战:实现一个动态平滑折线图
android·折线图·compose
李艺为6 小时前
Fake Device Test作假屏幕分辨率分析
android·java
zh_xuan6 小时前
github远程library仓库升级
android·github
峥嵘life6 小时前
Android蓝牙停用绝对音量原理
android
小书房6 小时前
Kotlin的内联函数
java·开发语言·kotlin·inline·内联函数
czlczl200209257 小时前
IN和BETWEEN在索引效能的区别
android·adb
Volunteer Technology7 小时前
ES高级搜索功能
android·大数据·elasticsearch
北京自在科技8 小时前
Find Hub App 小更新
android·ios·安卓·findmy·airtag
lbb 小魔仙8 小时前
2026远程办公软件夏季深度横测:ToDesk、向日葵、网易UU远程全面对比,远控白皮书
android·服务器·网络协议·tcp/ip·postgresql
coding_fei8 小时前
AudioServer初始化过程
android