Jetpack Compose中UI数据刷新

前言

Jetpack Compose中想更新界面上的任何东西都需要重组,重组本质就是再执行一次当前函数。

触发重组方式有

  • State值改变
  • 调用方法刷新

State

创建State有以下几种方式

image-20240331111403128

注意

只有在Kotlin中才能生效,在Java中是不行的。

对象

State需要注意的点:

一定是要State对象本身不变,State的值改变才行,其中很多不熟悉kotlin泛型时经常出现的坑是:

1
2
3
4
5
6
7
8
9
10
11
//假设有个User data类
val stete = mutableStateOf(User())
val user = stete.value
//这种情况是不会触发重组的,这里修改的user对象内部的属性,并没有改变stete.value
user.name = "new value"
//还有一种更常用的写法,使用by关键字,by是kotlin的语法糖
var user:User by mutableStateOf(User())
//State的by是对stete.value的包装,state.value.name = "new value" 完全等于 user.name = "new value"
//所以user.name = "new value"并不会重组
//这样才能改变state的值,copy函数会创建新对象
state.value = state.value.copy(name = "new value")

state.value底层重写了getter/setter(kotlin语法),它并不是一个单纯属性,还包括了set、get函数,进行赋值时调用set函数,默认使用equals比较新旧值,不一致时发送重组通知,在上述例子中最经典的就是user.name = "new value"根本没过state.value的set函数,也就没重组。

集合

对于集合

MutableCollection重写过的改变内容的函数如:add、set、remove等;

1
2
3
4
5
6
7
val list = mutableStateListOf<User>()
//会更新
list.add(User())
//不会更新
list[index].name = "new value"
//会更新
list[index] = list[index].copy(name = "new value")

List的中括号[]是对get函数的语法糖,get不会改变集合内容,而[]=(有等号)是对set函数语法糖,可以改变内容。

调用方法

在Composable函数中使用currentRecomposeScope获得RecomposeScope对象,在需要的地方执行recomposeScope.invalidate()即可重组所在作用域,重新执行代码本身就会重新读取变量,全手动可以不需要state。

1
currentRecomposeScope.invalidate()