Jetpack Compose 的状态

2023 年 8 月 21 日 星期一(已编辑)
3

Jetpack Compose 的状态

众所周知一个正常的变量在 Android 视图中发生更新时是不会触发任何事件的, 需要想各种方法(LiveData, Databinding, Observe, ViewModel) 等各种方法让它在更新时重绘视图以及不同情况下保存变量值

为此,Compose 需要知道要跟踪的状态,以便在收到更新时安排重组

Compose 采用特殊的状态跟踪系统,可以为读取特定状态的任何可组合项安排重组。这让 Compose 能够实现精细控制,并且仅重组需要更改的可组合函数,而不是重组整个界面。这将通过同时跟踪针对状态的“写入”(即状态变化)和针对状态的“读取”来实现

在组件函数中保持值更新

可组合函数中的记忆功能

需要使用 StateMutableState 类型来让 Compose 知晓其状态: kotlin @Composable fun WaterCounter(modifier: Modifier = Modifier){ // 使用 by 进行委托 var count by mutableStateOf(0) Column (modifier = Modifier.padding(16.dp)) { Text( text = "You've had $count glasses.", ) Button(onClick = { count++ }, Modifier.padding(top = 8.dp)) { Text("Add") } } }

但是这还不够, 首先这个可组合函数是一个函数, 而在每次 mutableStateOf 内的值更新时会引发该组件重组, 因此会导致其 count 的值重新赋值为0, 从而导致没有效果 所以我们还需要引入一个 remember 来让初始组合时的 count 存储起来并一直保持不被重组重赋 kotlin var count by remember { mutableStateOf(0) }

现在它们能工作了

而你有时候可能会遭遇例如:亮暗色主题切换、语言切换或横竖切换 此时 Activity 会被重组, 此时需要用到 rememberSaveable, 不然当 Activity 被重组时,状态依旧会被刷新清除掉

状态控制组件

状态驱动型界面

@Composable
fun WaterCounter(modifier: Modifier = Modifier) {
   Column(modifier = modifier.padding(16.dp)) {
       var count by remember { mutableStateOf(0) }

       if (count > 0) {
           // This text is present if the button has been clicked
           // at least once; absent otherwise
           Text("You've had $count glasses.")
       }
       Button(onClick = { count++ }, Modifier.padding(top = 8.dp)) {
           Text("Add one")
       }
   }
}

count 大于 0 时 Text 会显示!

状态驱动界面在给定时刻显示哪些元素 界面的不同部分可以依赖于相同的状态, 修改 Button, 使其在 count 达到 10 之前处于启用状态,并在达到 10 之后停用(即您达到当天的目标), 为此, 请使用 Button 的 enabled 参数

Button(onClick = { count++ }, Modifier.padding(top = 8.dp), enabled = count < 10) {  
    if(count >= 10){  
        Text("Enough")  
    }else{  
        Text(text = "Add")  
    }
}

状态提升

状态提升

上文中, 将 count 存储在组件中, 该组件即被称作有状态组件, 但是,具有内部状态的可组合项往往不易重复使用,也更难测试 , 这是事实, 因为组件如果带了状态的话那么大部分情况下它应该比较特殊,至少重复使用的概率会比较低 原本: kotlin @Composable fun WaterCounter(modifier: Modifier = Modifier) { var count by rememberSaveable { mutableStateOf(0) } Column { if (count > 0) { Text("You've had $count glasses.") } Button(onClick = { count++ }, Modifier.padding(top = 8.dp), enabled = count < 10) { Text("Add one") } }}

无状态化后: ```kotlin @Composable
fun WaterStateCounter(modifier: Modifier = Modifier) {
var count by rememberSaveable {
mutableStateOf(0)
}
WaterCounter(count, { count++ })
}

@Composable
fun WaterCounter(count:Int, onCountChange: () -> Unit, modifier: Modifier = Modifier){
Column {
if (count > 0) {
Text("You've had $count glasses.")
}
Button(onClick = { onCountChange() }, Modifier.padding(top = 8.dp), enabled = count < 10) {
Text("Add one")
}
}} ```

现在 WaterCount 的复用性更高了, 并且在 WaterStateCounter 中如果有其它组件需要调用 count 值也更为方便了

并且重组是对单组件发生的, WaterStateCount 所依赖的变量未发生变化的话整个组件则只有依赖了 count 的组件会发生重组(在 count 修改时)

摘抄: 提升状态时,有三条规则可帮助您弄清楚状态应去向何处:

  1. 状态应至少提升到使用该状态(读取)的所有可组合项的最低共同父项
  2. 状态应至少提升到它可以发生变化(写入)的最高级别
  3. 如果两种状态发生变化以响应相同的事件,它们应提升到同一级别

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...