当前位置:网站首页>State Management in Jetpack Compose
State Management in Jetpack Compose
2022-08-02 09:08:00 【RikkaTheWorld】
文章目录
1. 概述
Compose Is described using declarative UI, @Composable Comments must be modified by the function is a pure function has no return value,If any side effects is also controlled,Side effects of management Effect,Then to know.
Functional programming is contradictory and state machines、冲突的.假设有这么一个场景:There is a display copyTextView,和一个Button,每次点击 Button,All want to change TextView On the copy:
var id = 0
...
Column {
Text(text = "$id") // Show the copy TextView
TextButton(onClick = {
id++ // // 每次点击 Button 都对 id 加1
How to change the above here Text 的文案??????
}) {
Text(text = "Click on the I id 加1")
}
}
因为 Text 、 TextButton Is is Composable Modified can combine items,We can't go in a composable item reference another can combine items,That we how to update Text In the document?
Jetpack Compose Provide some of the state API, It associated with the state and the items which are combined,To solve the above questions.
2. 状态的更新 和 remember Api
Compose Only the only means of update:A new parameter to call can combine items,触发 Compose 重组.
Please see the following official code:
@Composable
fun HelloContent() {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Hello!",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.h5
)
OutlinedTextField(
value = "",
onValueChange = {
},
label = {
Text("Name") }
)
}
}
This page shows the static,没有任何反应,我们甚至不能在 OutlinedTextField 中输入文字:
Jetpack 提供了 remeber Api 用于存储属性, Its object will be stored in memory.
2.1 remember api
在初始组合期间(The initialization page),remember Calculated value will be stored in the combination of,And during the restructuring,Returns the stored value.
Create a usage as follows:
val name: String = remember {
"rikka" }
remember Function returns a composable item,It will cache in our lambda Expression to create the value of the,Because it can combine the properties of the,So it can exist as a combination of state and.
2.2 可观察对象 MutableState
上面的代码中,使用 remember Created by the state is immutable, But in most cases state is variable,So, in order to introduce the mechanism of variable, Compose Provides an observable model: MutableState , It can change in value when the updateUI.
interface MutableState<T> : State<T> {
override var value: T
}
MutableState Is a variable value holders, 在执行 Composeable During the function to read value 值,当前的 RecomposeScope Subscribe to the value of reading and writing will be.当更改 value 属性时,Will notify any subscribed to the value of RecomposeScope,Will trigger the restructuring.
这里注意:如果 value 被更改了,But the changes before and after the attributes,The restructuring is not going to happen.
我们可以使用 mutableStateOf 来创建它,并且用 remember 包装它,In order to can combine items used in the, 代码如下:
val name: MutableState<String> = remember {
mutableStateOf("rikka") }
// 状态的更新:
Text(
modifier = Modifier.clickable {
name.value = "vera" },
text = name.value
)
We can use attributes to entrust, 使用 by 来解包 MutableState:
var name: String by remember {
mutableStateOf("rikka") }
Text(
modifier = Modifier.clickable {
name = "vera" },
text = name
)
2.3 LiveData、Flow、RxJava
在 Android 中,We often use in logic layer LiveData、 Flow As the observed object, 而非 MutableState,也就是说 LiveData、 Flow、 Observable Can't direct to Compose 上套.这该怎么办呢? 难道要用 MutableState 再去观察 LiveData?
Jetpack 提供了这种支持,It supports the above several commonly used observable model into MutableState.
LiveData转化成MutableState,使用observeAsState:
// ViewModel
private val _name = MutableLiveData("rikka")
val name: LiveData<String>
get() = _name
// UI 层
val name by viewModel.name.observeAsState()
Text(
text = name ?: "",
)
Flow转化成MutableState, 使用collectAsState:
// ViewModel
private val _name = MutableStateFlow("rikka")
val name: StateFlow<String>
get() = _name
// UI 层
val name by viewModel.name.collectAsState()
Text(
text = name,
)
- Rx 转化成
MutableState,使用subscribeAsState:
val name: String by observable.subscribeAsState("rikka")
Text(
text = name
)
So we can continue to use in your code LiveData、Flow ,And don't have to worry about they can't and Compose Proceed to the linkage.
2.4 After configuration changes the state of the maintain
Sometimes our configuration may change,For example, the typical flip the screen,So using the original remember Storage will be lost,To reset the state.
所以 Jetpack 提供了 rememberSaveable 来解决这个问题, 它内部使用 Bundle To the cache state,Made after the configuration change,Can still keep fit, 就像 Activity 的 onSaveInstanceState 一样, 使用方法也很简单:
var name: String by rememberSaveable {
mutableStateOf("rikka") }
3. 状态提升
根据上面所述, Can combine item is divided into state,And there is no state.
这会有一个问题: Stateful can combine items,Although you can change,但是Not easy to be reused elsewhere,Also more difficult to test,It's a bit like pure functions and the distinction that are not pure functions.
而 Compose 提出了一种“状态提升”的概念,With state of the items which are combined into two can combine items:
- 可组合项 A
In general store two parameters:
①:value: T, 即当前状态
②:onValueChange: (T) -> Unit,状态改变时的回调,建议T是新值
The two calls can combine items B - 可组合项 B:
将value、onValueChangeThe state information as arguments,Yourself to avoid storage state, The state is its own state
For example, it is a item can be combined with state:
@Composable
fun HelloContent() {
Column(modifier = Modifier.padding(16.dp)) {
var name by rememberSaveable {
mutableStateOf("rikka") } // 1. 状态
if (name.isNotEmpty()) {
Text(
text = "Hello, $name!",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.h5
)
}
OutlinedTextField(
value = name,
onValueChange = {
name = it }, // 2. State change callback
label = {
Text("Name") }
)
}
}
由于注释1、2 的存在, HelloContent Bad function test and reuse,So the use of state here,优化后的代码如下所示:
// 可组合项 A
@Composable
fun HelloContent() {
var name by rememberSaveable {
mutableStateOf("") }
HelloContent(name = name, onNameChange = {
name = it })
}
// 可组合项 B
@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Hello, $name",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.h5
)
OutlinedTextField(
value = name,
onValueChange = onNameChange,
label = {
Text("Name") }
)
}
}
上面代码中,可组合项 A 就是把状态“提上来”的函数. 可组合项BMuch easier to reuse and test.
状态提升,Look on the bright said is down a pure function、提高UIOr the degree of reuse state(解耦了), Speaking bad but is overloaded、化简为繁.
If you think you can combine items、State will not be reuse,Or at least in a short period of time will not be others to use,Nor do state the necessity of ascension.
4. 状态容器
We can use the items which are combined to store state,And when it comes to the above.
But in more complex situations,For example, there are a number of different sources of state scene,Just use of state,Readability is not so good,And difficult to conform to the principle of a single trusted,所以 Compose And provides additional two solutions:
- Build the ordinary state container
To build a data classes and can combine items,To entrust a can combine all the state and logic (Belong to the state of ascension, updated version) - Move the state to ViewModel 中去
使用 ViewModel And additional data classes, To entrust the page level UI All of the state and logic
The above is the difference between the two:
The ordinary state of container management UI 是小的、微观的,Only for a composable item;
而 ViewModel 管理的 UI Is big、宏观的,可能针对 n Can be combination of, 其次,Its life cycle longer.
4.1 Build the ordinary state container
例如,我们的一个 MyApp 的可组合项:
@Composable
fun MyApp() {
ComposeTheme {
val scaffoldState = rememberScaffoldState() // 1
val shouldShowBottomBar = shouldShowBottomBar() //2
Scaffold(
scaffoldState = scaffoldState,
bottomBar = {
if (shouldShowBottomBar) {
BottomBar(
tabs = BTTOM_BARS_TAB, // 3
navigateToRoute = {
navigateToBottomBarRoute(it) // 4
}
)
}
}
) {
NavHost(navController = navController, "initial") {
/* ... */ } // 5
}
}
}
In the above items which are combined MyApp,A comment1、2、3 处的状态,和注释4、5The behavior logic, 很明显,Use of state also pretty trouble,可读性不好,看起来很绕,Because after ascending function may be5个参数.
Below to build the general state of the container,We first construct a data class,专门存放 MyApp 所有的UI状态和行为:
class MyAppState(
val scaffoldState: ScaffoldState,
val navController: NavHostController,
/* ... */
) {
val bottomBarTabs = ...
val shouldShowBottomBar: Boolean
get() = /* ... */
fun navigateToBottomBarRoute(route: String) {
/* ... */ }
}
接下来,使用 rember Api ,Given in to the data classes can combine items stored in the ability:
@Composable
fun rememberMyAppState(
scaffoldState: ScaffoldState = rememberScaffoldState(),
navController: NavHostController = rememberNavController(),
/* ... */
) = remember(scaffoldState, navController, /* ... */) {
MyAppState(scaffoldState, navController, /* ... */)
}
最后优化 MyApp
@Composable
fun MyApp() {
MyTheme {
val myAppState = rememberMyAppState()
Scaffold(
scaffoldState = myAppState.scaffoldState,
bottomBar = {
if (myAppState.shouldShowBottomBar) {
BottomBar(
tabs = myAppState.bottomBarTabs,
navigateToRoute = {
myAppState.navigateToBottomBarRoute(it)
}
)
}
}
) {
NavHost(navController = myAppState.navController, "initial") {
/* ... */ }
}
}
}
优化后的 MyApp 注重于 UI 的构建,All of the state and behavior all entrusted to the MyAppState,通过和 rememberMyAppState 配套,解耦了UI和逻辑.
4.2 ViewModel
ViewModel 因为其本身的特性,So is also a good container storage page state and logic. It is more suitable for storage level screen state and logic(宏观的),例如 UiState.
举个例子, 我们有下面的 UiState,Used to represent a page state:
data class ExampleUiState(
val dataToDisplayOnScreen: List<Example> = emptyList(),
val userMessages: List<Message> = emptyList(),
val loading: Boolean = false
)
那么在 ViewModel 中可以这样写:
class ExampleViewModel(
private val repository: MyRepository,
private val savedState: SavedStateHandle
) : ViewModel() {
var uiState by mutableStateOf(ExampleUiState()) // 这里无论是 LiveData、Flow 还是 Rx,都可以转化成 MutableState
private set
// Business logic
fun somethingRelatedToBusinessLogic() {
/* ... */ }
}
最后 UI 层的使用:
@Composable
fun ExampleScreen(viewModel: ExampleViewModel = viewModel()) {
val uiState = viewModel.uiState
/* ... */
ExampleReusableComponent(
someData = uiState.dataToDisplayOnScreen,
onDoSomething = {
viewModel.somethingRelatedToBusinessLogic() }
)
}
@Composable
fun ExampleReusableComponent(someData: Any, onDoSomething: () -> Unit) {
/* ... */
Button(onClick = onDoSomething) {
Text("Do something")
}
}
5. 总结
- Compose The items which are combined with state and behavior can be,为了更新 UI,Will be in a different state(参数)To call on one side can combine items
- In order to facilitate let us 改变状态 触发 改变UI, Compose 提供了
rememberapi 和MutableState,The interaction of the two,Can make us easily observable states in the construction of the,即像 MVVM 那样, ViewModel 的变化可以(自动)更新 V 层 remember提供了一些 api,可以帮助 Android MVVM Architecture and better Compose 结合, Such as providing the Flow、 LiveData、Rx 转化成 MutableState 的能力- Compose There are four items which are combined state management way
① 躺平型: 所有的 状态、Logic in its portfolio in the item, This will lead to items which are combined bloated、 可读性低、复用能力差
② 状态提升: 将所有的状态、Logic into a composable itemA中,To call can combine itemsB, 可组合项B的状态、Behavior is its parameters. 这样的话, 可组合项B就是无状态、Reusable, 而状态、Behavior of the management on the items which are combined A 中
③Build the ordinary state container: Will a can combine all the status of the item、Logic into a data class,通过rememberapi Given its storage capacity,So that we can manage a complex state、Logic can combine items
④ViewModel 管理状态:Multiple items which are combined all the state of the、Logic into a data class,通过rememberapi Given its storage capacity,Compared with the more macro,可以管理整个 UI 的状态,例如UiState属性
参考文章
边栏推荐
- Fiddler(七) - Composer(组合器)克隆或者修改请求
- Pycharm (1) the basic use of tutorial
- 膜拜,Alibaba分布式系统开发与核心原理解析手册
- Nodejs3day(express简介,express创建基本Web服务器,托管静态资源,nodemon下载及出现的问题,中间件,编写GET,POST,JSONP接口)
- USACO美国信息学奥赛竞赛12月份开赛,中国学生备赛指南
- js函数防抖和函数节流及其使用场景
- UVM之sequence机制
- mysql 中 in 的用法
- JSP页面中page指令有哪些属性及方法可使用呢?
- Jenkins--基础--6.1--Pipeline--介绍
猜你喜欢
随机推荐
next permutation
Jenkins--基础--5.4--系统配置--全局工具配置
Jenkins--基础--6.2--Pipeline--语法--声明式
Redis分布式锁入门
Jenkins--基础--6.3--Pipeline--语法--脚本式
Codeforces Round #811 (Div. 3)无DF
【打新必读】麦澜德估值分析,骨盆及产后康复电刺激产品
Jenkins--部署--3.1--代码提交自动触发jenkins--方式1
etcd implements large-scale service governance application combat
四字节的float比八字结的long范围大???
Golang ORM框架 — GORM
day_05 time 模块
houdini 求出曲线的法向 切线以及副法线
【微信小程序2】事件绑定
自定义卡包效果实现
spark:商品热门品类TOP10统计(案例)
软件exe图标变记事本或浏览器、360压缩打不开的几种应急解决方法
LeetCode_2357_使数组种所有元素都等于零
类和对象【下】
边缘计算开源项目概述









