Compose-状态
应用中的状态是指可以变化的任何值,从Room数据库到类的变量,全部涵盖在内
1.UI更新循环
在Android应用程序中,状态会根据事件进行更新。事件是从我们的应用程序外部生成的输入,例如用户点击按钮。
- 事件-事件由用户或程序的其他部分生成
- 更新状态-事件处理程序更改UI使用的状态
- 显示状态-更新UI以显示新状态
2.非结构化状态
当添加更多事件和状态时,可能会出现几个问题:
- 测试:由于UI的状态与Views代码交织在一起,因此很难测试此代码
- 部分状态更新:当屏幕由更多事件时,很容易忘记更新部分状态以响应事件。因此,用户可能会看到不一致或不正确的UI
- 部分UI更新:由于我们在每次状态更改后手动更新UI,因此有时很容易忘记这一点,因此,用户可能会字其UI中看到随机更新的陈旧数据
- 代码复杂性:在这种模式下编码时很难提取一些逻辑,结果,代码有变得难以阅读和理解的趋势
3.单向数据流
为了帮助解决非结构化状态的这些问题,我们引入了ViewModel和LiveData
我们将状态从Activity移到了ViewModel,在ViewModel中,状态由LiveData表示。LiveData是一种可观察状态容器,意味着它可以让任何人观察状态的变化。然后,我们在界面中使用observe方法,以便在状态变化时更新界面
1 | class HelloViewModel : ViewModel(){ |
通过以这种方式构建代码,我们可以将事件”向上”流动到ViewModel。然后,为了响应事件,ViewModel将进行一些处理,而且可能会更新状态。状态更新后,会”向下”流动到Activity
单向数据流是一种状态向下流动而事件向上流动的设计,它的优势有:
- 可测试性:通过将状态与显示它的UI分离,可以更轻松地测试ViewModel和Activity
- 状态封装:因为状态只在一个地方(the ViewModel)更新,随着UI的增长,不太可能引入部分状态更新错误
- UI一致性:所有状态更新都通过使用可观察状态持有者立即反映在UI中
4.重组与remember
在命令式界面模型中,如需更改某个组件,可以在该组件上调用setter更改其内部状态。在Compose中,可以使用新数据再次调用可组合函数。这样做会导致函数进行重组——系统会根据需要使用新数据重新绘制函数发出的组件。Compose框架可以智能地仅重组已更改的组件。
4.1 将内存引入可组合函数
remember提供了可组合函数内存
系统会将由remember计算的值存储在组合树中,而且只有当remember的键发生变化时才会重新计算该值
可以将remember看作是为函数提供单个对象的存储空间,过程与private val属性在对象中执行操作相同
4.2 有状态与无状态
使用remember存储对象的可组合项会创建内部状态,使该可组合项有状态
在调用方不需要控制状态,并且不必自行管理状态便可使用状态的情况下,”有状态”会非常有用。但是,具有内部状态的可组合项往往不易重复使用,也更难测试
无状态可组合项是指不保证任何状态的可组合项。实现无状态的一种简单方法是使用状态提升
5.MutableState
在组合中创建State
MutableState
当应用于可组合项时,这通常意味着向可组合项引入两个参数
- value: T - 要显示的当前值
- onValueChange: (T) -> Unit - 请求更改值的事件,其中T是建议的新值
MutableState此函数使用remember向自身添加内存,然后在内存中存储mutableStateOf,以创建MutableState
对value进行的任何更改都会自动重组用于读取此状态的所有可组合函数
通过以下MutableState三种方式声明一个可组合对象:
- val state = remember{ mutableStateOf(default) }
- var value by remember{ mutableStateOf(default) }
- val (value,setValue) = remember{ mutableStateOf(default) }