启动效果
让我们在可组合对象中运行挂起函数。当LaunchedEffect进入Composition时,它会启动一个协程,并将代码块作为参数传递。如果它有多个键和一个变化,则现有的协程将被取消,并在新的协程中启动新的挂起功能。
class HomeScreenViewModel : ViewModel() {
private val _uiEvent = MutableSharedFlow<UiEvent>(0)
val uiEvent: SharedFlow<UiEvent> = _uiEvent.asSharedFlow()
}
@Composable
fun HomeScreen(
viewModel: HomeScreenViewModel = viewModel(),
) {
val scaffoldState = rememberScaffoldState()
LaunchedEffect(key1 = true) {
viewModel.uiEvent.collect { event ->
when (event) {
is UiEvent.SnackBar -> {
scaffoldState.snackbarHostState.showSnackbar(
"SnackBar"
)
}
}
}
}
}
在上面的代码中,我们collects从 viewModel 启动了一个 uiEvents 的协程,当收集到的事件是 a 时,UiEvent.SnackBar我们会显示一个小吃店。
副作用
每次成功的组合都会调用它,如果组合失败,则不会执行此代码块
如果没有SideEffect,则timer++不会触发重组,因为它在重组时发生了更改,并且它会通知您启动调用应该发生在 aLaunchedEffect而不是composition内。
@Composable
fun Timer() {
val coroutineScope = rememberCoroutineScope()
var timer by remember {
mutableStateOf(0)
}
timer++
coroutineScope.launch {
delay(1000)
}
Text(text = timer.toString())
}
有了SideEffect,timer++就会触发重组。这将创建一个计时器循环,您也将摆脱启动错误。
一次性效果
用于检测DisposableEffect键是否更改的取消,可组合项需要处理(进行清理)。
例如,我们希望在用户看不到应用程序时停止计时器。
@Composable
fun Timer(
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
timer: Int,
onStartTimer: () -> Unit,
onStopTimer: () -> Unit,
) {
DisposableEffect(key1 = lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_START) {
onStartTimer()
} else if (event == Lifecycle.Event.ON_STOP) {
onStopTimer()
}
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
Text(text = timer.toString())
}
记住协程作用域
让我们在可组合之外启动一个协程,但其作用域是一旦离开组合就会自动取消。此外,您可以在需要手动控制一个或多个协程的生命周期时使用它,例如,显示一个ModalBottomSheet.
@Composable
fun MyScreen(
modalBottomSheetState: ModalBottomSheetState,
) {
// Creates a CoroutineScope bound to the MyScreen's lifecycle
val scope = rememberCoroutineScope()
ModalBottomSheetLayout(
sheetContent = {
/* ... */
}
) {
Button(
onClick = {
// Creates a new coroutine to show
// the modal bottom sheet
scope.launch {
modalBottomSheetState.show()
}
}
) {
Text(text = "Click me")
}
}
}
记住更新状态
它保证我们总是得到最新的状态变量变化。
@Composable
fun Timer(
timer: Int
) {
val updatedTimer by rememberUpdatedState(timer)
LaunchedEffect(key1 = Unit) {
delay(1000L)
Log.d("Track", "$updatedTimer")
}
}
生产状态
将非 Compose 状态转换为Compose状态,并启动协程。
@Composable
fun Screen() {
val counter: State<Int> = produceState(initialValue = 0) {
delay(200L)
value = 4
}
Text(text = "${counter.value}")
}
在上面的代码中,我们生成了 aState<Int>并启动了一个协程,在其中添加了一个延迟,之后,我们为 counter 分配了一个新值
派生状态
当某个状态从其他状态对象计算或派生时使用。每当计算中使用的状态之一发生更改时,这将触发。
@Composable
fun ReceiptList(filter: String) {
val receipts = remember {
mutableStateListOf<String>()
}
val filteredReceipts by remember(filter) {
derivedStateOf {
receipts.filter {
it.contains(filter)
}
}
}
LazyColumn {
items(filteredReceipts) { /* ... */ }
items(receipts) { /* ... */ }
}
}
在上面的代码中,derivedStateOf保证每当收据发生变化时,都会进行filteredReceipts 计算并更新 UI。如果过滤器值发生变化,remember 块将被执行并创建一个新的派生状态对象。
快照流
它用于将Compose 状态对象转换为冷Flow。
@Composable
fun ReceiptList(
showFloatingActionButton: () -> Unit
) {
val lazyListState = rememberLazyListState()
LaunchedEffect(key1 = lazyListState) {
snapshotFlow { lazyListState.firstVisibleItemIndex }
.collect {
if (it == 0) {
showFloatingActionButton()
}
}
}
}
在上面的代码中,如果lazyListState.firstVisibleItemIndex为 0,我们将显示FAB。
我希望这篇文章能让你对Jetpack Compose Side-effects有一个基本的了解。
来源:https://daniatitienei.hashnode.dev/side-effects-in-jetpack-compose
网友评论