前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Compose_State 状态

Compose_State 状态

作者头像
mikimo
发布2024-08-12 08:15:23
480
发布2024-08-12 08:15:23
举报
文章被收录于专栏:iOS开发~

1、state

使用 StateMutableStateCompose 能够观察到状态。 Compose 会跟踪每个使用了 State.value 的可组合函数,并在其 value 发生变更时出发重组。 创建 State

代码语言:javascript
复制
mutableStateOf(T)

// 对基础类型进行了优化的初始化方法
mutableIntStateOf(0)
mutableLongStateOf(0)
mutableFloatStateOf(0.0)
mutableDoubltStateOf(0.0)

例:

代码语言:javascript
复制
Column {
	val count: MutableState<Int> = mutableIntStateOf(0)
	Text("Count: ${count.value}")
	Button(onClick = { count.value++ }) { Text("Add") }
}

count 发生变更时会触发重组,但变量 count 每次都会初始化为 0,所以观察不出变化,需要使用 remember 保留此值。

2、remember

2.1 remember 和 mutableStateOf

remember 可组合内嵌函数,系统会在初始组合期间将 remember 计算的值存储在组合中,并在重组期间一直保持存储的值。

代码语言:javascript
复制
var value by remember { mutableStateOf(default) }
val (value, setValue) = remember { mutableStateOf(default) }

例:

代码语言:javascript
复制
Column {
	val count: MutableState<Int> = remember { mutableStateOf(0) }
	Text("Count: ${count.value}")
	Button(onClick = { count.value++ }) { Text("Add") }
}

此时计数器已可正常使用并显示了。

2.2 remember 其他用法
代码语言:javascript
复制
remember {
	// do once code
}
// remember 里的语句仅会执行一次
代码语言:javascript
复制
remember(userId) {
	// refresh profile
}
// 当 remember 的参数 userId 发生改变时,会重新执行 remember 里的语句
2.3 使用 remember 注意事项
  • 避免不必要的重组
  • 仅保存轻量级引用,可只在 Compose 中保存一个轻量级的引用,如唯一标识或键值等,在需要时从外部源(如:数据库或 ViewModel)获取完整对象。
  • 利用 remember 的键值参数,保持仅在参数变化时对象才会被重新创建,避免不必要的对象创建和回收

3、by

by 委托属性,即将一个对象的属性委托给另一个对象。在该场景下可通过 byState 的属性委托给另一个对象。如:

代码语言:javascript
复制
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
Column {
	val count by remember { mutableStateOf(0) }
	Text("Count: ${count}")
	Button(onClick = { count++ }) { Text("Add") }
}

通过 byMutableStateOf<Int>value 属性委托给了 count,可以直接通过 countvalue 进行增删改查。


4、rememberSaveable

remember 会在 activity 重新创建后忘记状态,如:旋转屏幕、更改语言、切换 light / dark 模式等。这种场景下还想保持状态则需要用到 rememberSaveablerememberSaveable 会自动保存可保存在 Bundle 中的任何值。(其他值需要转换成 Saver 对象)。

代码语言:javascript
复制
Column {
	val count by rememberSaveable { mutableStateOf(0) }
	Text("Count: ${count}")
	Button(onClick = { count++ }) { Text("Add") }
}

5、State hoisting

将状态外移至可组合项的调用方,使可组合项变成无状态的模式。

Tips:在设计可组合函数时,您应该让可组合函数拥有尽可能少的状态

常用的状态提升模式是将状态变量替换为两个参数:

  • value: T:当前值
  • onValueChange: (T) -> Unit:请求更改值 例如:
代码语言:javascript
复制
fun StatelessCounter(count: Int, onIncrement: () -> Unit) {
	Column {
		Text("Count: ${count}")
		Button(onClick = onIncrement) { Text("Add") }
	}
}

Tips:仅传递可组合函数所需的状态,以避免不必要的重组并提高可重用性。

6、ViewModel

最好将状态和逻辑迁移到 viewModel 中,跟页面进行分离,使用 viewModel 统一管理状态,有以下优势:

  • 单一可信来源:确保只有一个可信来源,避免状态不一致等bug。
  • 可共享:可与多个可组合函数共享状态。
  • 可拦截:无状态可组合函数的调用方,在状态更改时可决定是否忽略或修改其刷新。
  • 分离:将无状态可组合函数的状态跟页面进行分离。
6.1、创建 viewModel 类
代码语言:javascript
复制
import androidx.lifecycle.ViewModel

class CounterViewModel: ViewModel() {
	private val _count = mutableOfState(0)
    val count: MutableOfState<Int>
        get() = _count

   fun add() {
		_count++
   }
   fun minus() {
   		_count--
   }
}
6.2、使用 viewModel

可以通过 viewModel() 函数,从任何可组合函数访问此 ViewModel 需在 app/build.gradle.kts 文件添加依赖:

代码语言:javascript
复制
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:{2.8.4}")

最新版本见:Lifecycle

使用如下:

代码语言:javascript
复制
fun StatelessCounter(
	viewModel: CounterViewModel = viewModel()
) {
	Column {
		Text("Count: ${viewModel.count}")
		Button(onClick = viewModel.add()) { Text("Add") }
		Button(onClick = viewModel.minus()) { Text("Minus") }
	}
}

7、List

列表式数据使用 toMutableStateList 将列表数据整体转换为可观测状态。将数据和业务逻辑都收敛到 ViewModel里:

代码语言:javascript
复制
import androidx.compose.runtime.toMutableStateList

class Task(
	val id: Int,
    val count: Int,
    initialChecked: Boolean = false
) {
    var checked by mutableStateOf(initialChecked)
}

fun getTasks() = List(30) { i -> Task(i) }

class TaskViewModel: ViewModel() {
	// 数据,外部仅可读
	private val _tasks = getTasks().toMutableStateList()
    val tasks: List<Task>
        get() = _tasks

    fun remove(item: Task) {
        _tasks.remove(item)
    }
    // 业务逻辑
    fun changeTaskChecked( item: Task, checked: Boolean) {
        _tasks.find { it.id == item.id }?.let { task ->
            task.checked = checked
        }
    }
}

列表式数据UI:

代码语言:javascript
复制
fun TasksList(
    viewModel: TaskViewModel = viewModel()
) {
    LazyColumn(state = rememberLazyListState()) {
        items(
            items = viewModel.tasks,
            key = { task -> task.id }
        ) { task ->
    		Row {
        		Text("Task: ${task.count}")
        		Checkbox(
        			checked = task.checked, 
        			onCheckedChange = { checked ->
                		viewModel.changeTaskChecked(task, checked)
                	}
        		)
    		}
        }
    }
}

Reference: State in Jetpack Compose State and Jetpack Compose ViewModel Restoring state in Compose Android Compose remember() 及 重組作用域

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-08-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、state
  • 2、remember
    • 2.1 remember 和 mutableStateOf
      • 2.2 remember 其他用法
        • 2.3 使用 remember 注意事项
        • 3、by
        • 4、rememberSaveable
        • 5、State hoisting
        • 6、ViewModel
          • 6.1、创建 viewModel 类
            • 6.2、使用 viewModel
            • 7、List
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档