文章目录
- Compose 生命周期和副作用
- 生命周期
- 副作用API
- DisposableEffect
- SIdeEffect
- LaunchedEffect
- rememberCoroutineScope
- rememberUpdatedState
- snapshotFlow
- produceState
- derivedStateOf
Compose 生命周期和副作用
生命周期
- OnActive:添加到视图树。即Composable被首次执行,在视图树上创建对应的节点。
- OnUpdate:重组。Composable跟随重组不断执行,更新视图树上的对应节点。
- OnDispose:从视图树移除。Composable不再被执行,对应节点从视图树上移除。
Composable在角色上更加类似于传统视图的View,所以没有Activity或者Fragment那样的前后台切换的概念,生命周期相对简单。
副作用API
副作用(Side-Effects):指在 Composable 函数中执行的可能会产生外部影响或依赖于外部资源的操作。如,访问数据库、网络请求、文件操作、弹出Toast、保存本地文件、访问远程或本地数据等。
重组可能会造成Composable频繁反复执行,副作用不应该跟随重组反复执行的。
为了处理副作用,Android Compose 提供了一系列副作用API。
DisposableEffect
DisposableEffect 可以感知 Composable 的 onActive 和 onDispose,允许通过副作用完成一些预处理和收尾处理。
@Composable
fun LifecyclePage() {var counter by remember { mutableStateOf(0) }Column(horizontalAlignment = Alignment.CenterHorizontally) {Text("Counter: ${counter}")Row {Button(onClick = { counter-- }) {Text("-")}Button(onClick = { counter++ }) {Text("+")}}}DisposableEffect(Unit) {Log.e("TAG", "预处理")counter = 100onDispose {Log.e("TAG", "销毁处理")}}
}
SIdeEffect
SIdeEffect 会在重组成功时执行,不适合处理那些耗时或者异步的副作用逻辑。
@Composable
fun LifecyclePage() {var counter by remember { mutableStateOf(0) }Column(horizontalAlignment = Alignment.CenterHorizontally) {Text("Counter: ${counter}")Row {Button(onClick = { counter-- }) {Text("-")}Button(onClick = { counter++ }) {Text("+")}}}SideEffect {Log.e("TAG", "hello 重组了")}
}
LaunchedEffect
用于异步操作。
当 Composable 进入 OnActive 时,LaunchedEffect 会启动协程执行 block 中的内容,可以在其中启动子协程或者调用挂起函数。当Composable 进入 OnDispose 时,协程会自动取消,因此 LaunchedEffect 不需要实现OnDispose{…}。
@Composable
fun LifecyclePage() {var counter by remember { mutableStateOf(0) }Column(horizontalAlignment = Alignment.CenterHorizontally) {Text("Counter: ${counter}")Row {Button(onClick = { counter-- }) {Text("-")}Button(onClick = { counter++ }) {Text("+")}}}LaunchedEffect(Unit) {async {delay(2000L)Log.e("TAG", "异步处理")counter = 2000}}
}
rememberCoroutineScope
协程操作。
LaunchedEffect 虽然可以启动协程,但是只能在 Composable 中调用。如果想在非 Composable 中使用协程,如点击事件中,可以使用 rememberCoroutineScope。
rememberCoroutineScope 会返回一个 CoroutineScope,并在 OnDispose 时自动取消。
@Composable
fun LifecyclePage() {var counter by remember { mutableStateOf(0) }val scope = rememberCoroutineScope()Column(horizontalAlignment = Alignment.CenterHorizontally) {Text("Counter: ${counter}") Button(onClick = {scope.launch {Log.e("TAG", "协程操作")counter = 3000}}) {Text("协程操作")}}
}
rememberUpdatedState
监听状态最新状态。
rememberUpdatedState的实现就明白其中原理了,其实就是remember和mutableStateOf的组合使用
@Composable
fun LifecyclePage() {var counter by remember { mutableStateOf(0) }val updateCounter by rememberUpdatedState(newValue = counter)Column(horizontalAlignment = Alignment.CenterHorizontally) {Text("Counter: ${counter}")Row {Button(onClick = { counter-- }) {Text("-")}Button(onClick = { counter++ }) {Text("+")}} Text("监听最新状态:${updateCounter}")}
}
snapshotFlow
snapshotFlow 可以把 Compose 的 State 状态对象转成协程的 Flow。
@Composable
fun LifecyclePage() {var time by remember { mutableStateOf("${System.currentTimeMillis()}") }val flow = snapshotFlow { time }Column(horizontalAlignment = Alignment.CenterHorizontally) {Button(onClick = {time = "${System.currentTimeMillis()}"}) {Text("更新")}}LaunchedEffect(Unit) {flow.collect {Log.e("TAG", "snapshotFlow: ${it}")}}
}
produceState
SideEffect 常用来将Compose的State暴露给外部使用,而produceState则相反,可以将一个外部的数据源转成State。外部数据源可以是一个LiveData或者RxJava这样的可观察数据,也可以是任意普通的数据类型。
data class Person(val name: String, val age: Int, val time: Long)@Composable
fun MyProduceState() {var name by remember { mutableStateOf("小明") }var age by remember { mutableStateOf(18) }val personState by produceState(initialValue = Person(name, age, System.currentTimeMillis()),name,age) {value = Person(name, age, System.currentTimeMillis())}Column(horizontalAlignment = Alignment.CenterHorizontally) {Button(onClick = { name = "小红" }) {Text("修改name")}Button(onClick = { age = 19 }) {Text("修改age")}Text("produceState: ${personState}")}
}
说明:修改 name 或 age 都会触发 produceState。
derivedStateOf
derivedStateOf用来将一个或多个State转成另一个State。derivedStateOf{…}的block中可以依赖其他State创建并返回一个DerivedState,当block中依赖的State发生变化时,会更新此DerivedState,依赖此DerivedState的所有Composable会因其变化而重组。
@Composable
fun MyDerivedStateOf() {var postList by remember { mutableStateOf(listOf("a", "b", "c", "d", "e")) }var keyword by remember { mutableStateOf("") }val result by remember {derivedStateOf { postList.filter { it.contains(keyword, false) } }}Text("过滤:${result}")Button(onClick = { postList = listOf("1", "2", "3", "4", "5") }) {Text("修改List")}OutlinedTextField(value = keyword, onValueChange = { keyword = it }, label = { Text("请输入") })
}
说明:当 postList 或 keyword 方式变化时,derivedStateOf 都会重新计算,result 也就更新了。