今天大概会聊到的范围
- SideEffect
- DisposableEffect
今天要讲的东西是 Side-Effect,很多场景下都有更好的 solution。以下多是为了举例而写出来的程序,请在实际使用前思考正确架构。
前情提要,上一篇有讲到如果我们在判断没有 persmission 时,就主动去 launch 并且试图取得 permission :
@Composable
fun CameraScreen() {
// 取得 context
val context = LocalContext.current
// 检查完 permission 後将答案存在 remember 中
var hasPermission by remember {
mutableStateOf(checkPermissionsGranted(context))
}
val permissionRequester = rememberLauncherForActivityResult(
contract = ActivityResultContracts.RequestPermission(),
) { isGranted: Boolean ->
hasPermission = isGranted
}
if (hasPermission) {
CameraView()
} else {
permissionRequester.launch(Manifest.permission.CAMERA) // error
}
}
程序会报错,会出现 Launcher has not been initialized 的错误。
原因是这样的,composable function 和一般 function 不同。他们的执行时间、执行次数都是由 compose-runtime 所决定。以这个例子为例,在 launcher ( permissionRequester
) 还没准备好的时候,CameraScreen
就会先被执行了好几次,因此会出现错误。
在 Compose 中,每一个 composable function 都可以视为一个 "接收参数并产生画面" 的 function。在这个定义下,所有与这个流程无关的资料改变、行为都属於 "副作用" side-effect。
举个例: ( anti-pattern 请勿学习 )
var count = 0
@Composable
fun SideEffectAntiPattern() {
count ++
}
因为我们无法控制 composable function 的执行次数、生命周期。当 composable function 内有异动到外部的资料、或是发出异步的 function (例如 network request ) 都有可能产生问题。
SideEffect
是一个可以让我们用来明确定义 side effect 效果的 composable function。 他可以让我们要执行的事情在 composition 完成後执行。
var count = 0
@Composable
fun SideEffectComposable() {
SideEffect {
count ++
}
}
SideEffect
还可以用来将 compose state 传递给无法使用 compose state 的物件:
@Composable
fun SideEffectComposable(window: Window) {
var color by remember { mutableStateOf(Color.Blue) }
SideEffect {
window.statusBarColor = color.toArgb()
}
}
有些时後,我们不仅是要在 composition 完成时触发事件,还要再 composable 要被回收时做一些 clean up 的动作。这时我们可以使用和 SideEffect
很类似的 DisposableEffect
val lifecycleOwner = LocalLifecycleOwner.current.lifecycle
DisposableEffect(lifecycleOwner) {
val lifecycle = lifecycleOwner
val observer = LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_PAUSE -> {
// do things
}
Lifecycle.Event.ON_RESUME -> {
// do things
}
Lifecycle.Event.ON_DESTROY -> {
// do things
}
}
}
lifecycle.addObserver(observer)
onDispose {
lifecycle.removeObserver(observer)
}
}
DisposableEffect
可以接收(也可以不提供)一个 key。当 composition 完成时,DisposableEffect
後面的 lambda 会执行。在 lambda 的最後,需要透过 onDispose
function 产生一个 DisposableEffectResult
。当 key 改变或是当 composable 被清除掉时,DisposableEffectResult
中的行为就会触发。
透过 SideEffect 和 DisposableEffect 可以间接碰触到 Composable 的生命周期,在正确的时机点执行。但这些可能都不是最好的做法(case by case),在 Compose 中,最好还是让 composable function 维持只有处理画面的部分,行为等可以往上提升到适当的阶层,或是透过 view model 等角色拉到外部去触发。
回到取得权限,因为我们需要在 composition 完成後执行 launcher.launch ,我们只需要简单将 launch 行为透过 SideEffect 包装起来就可以了。
if (hasPermission) {
CameraView()
} else {
SideEffect {
permissionRequester.launch(Manifest.permission.CAMERA)
}
}
今天的文章最後感觉没什麽收尾,那是因为我在研究 SideEffect 的过程,还有看到一系列的 state & effect API,不过感觉还没办法讲得很明白,所以决定之後再分享。
>>: 学习Python纪录Day18 - 散布图、长条图、圆饼图
看大家都写leetcode o3o Input 传入一个已排序好的阵列位置,把它变成se...
嗨大家好~我是凯西!接下来是我开学的三十天实力增进计画的纪录 规划上会刷leetcode加强我的py...
哎呀,自学了两个月後刚好碰到2021的铁人赛开打,顺便来分享一下我的学习过程好了,有错的在劳烦各位大...
国小造句最常见的题目就是:如果...就...,如果被打就会痛。对於程序语言也是有这样的语法给你作使用...
import pandas as pd reviews = pd.read_csv("./...