Jetpack Compose 可组合项生命周期及其常见处理Effect副作用API_jetpack compose return@(1)

if (state.hasError) {

    // 如果重组时scaffoldState.snackbarHostState发生变化,协程会被取消并重新创建并执行
    LaunchedEffect(scaffoldState.snackbarHostState) {
        // 展示Snackbar
        scaffoldState.snackbarHostState.showSnackbar(
            message = "Error message",
            actionLabel = "Retry message"
        )
    }
}

Scaffold(scaffoldState = scaffoldState) {
    /* ... */
}

}


state.hasError状态为 true时,会触发LaunchedEffect() 通过协程处理副作用;如果重组时state.hasError变成 false,协程会被取消,Snackbar也会消失。


#### rememberCoroutineScope()


LaunchedEffect 是由`@Composable` 标记的可组合函数,因此只能在其他可组合函数中使用(类似协程中的suspend)。当需要在可组合项外启动协程时(如onClick中),可以使用rememberCoroutineScope ,源码如下:



@Composable
inline fun rememberCoroutineScope(
getContext: @DisallowComposableCalls () -> CoroutineContext = { EmptyCoroutineContext }
): CoroutineScope {
val composer = currentComposer
val wrapper = remember {
CompositionScopedCoroutineScopeCanceller(
createCompositionCoroutineScope(getContext(), composer)
)
}
return wrapper.coroutineScope
}


rememberCoroutineScope() 返回 CoroutineScope 协程作用域,可以在可组合项外启动协程,该 CoroutineScope 绑定到调用它的组合点。**调用退出组合后,作用域将取消**。


使用示例:



@Composable
fun ComposeEffect() {
var txt by remember { mutableStateOf(“”) }
//rememberCoroutineScope在非重组作用域启动协程任务
val coroutineScope = rememberCoroutineScope()

Column(
    modifier = Modifier.fillMaxSize()wrapContentSize(Alignment.Center)
) {
    Text(text = txt)
    Button(onClick = {
        //在onClick中启动了协程
        coroutineScope.launch {
            delay(3000)
            txt = "修改文案"
        }
    }) {
        Text(text = "rememberCoroutineScope")
    }
}

}


点击Button后,启动协程,在协程中延迟3s重组并刷新Text文案。


#### DisposableEffect



@Composable
@NonRestartableComposable
fun DisposableEffect(
key1: Any?,
effect: DisposableEffectScope.() -> DisposableEffectResult
) {
remember(key1) { DisposableEffectImpl(effect) }
}


对于需要在键发生变化或可组合项退出组合后进行清理的副作用,可以使用 DisposableEffect。如果 DisposableEffect 中的key发生变化,那么就会执行onDispose()资源释放等操作,并重新执行DisposableEffect。


**DisposableEffect中强制以onDispose进行收尾,不加就会编译报错**。因此DisposableEffect适合有资源需要收尾的场景下。


使用示例:



@Composable
fun HomeScreen(
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
onStart: () -> Unit, // Send the ‘started’ analytics event
onStop: () -> Unit // Send the ‘stopped’ analytics event
) {
// Safely update the current lambdas when a new one is provided
val currentOnStart by rememberUpdatedState(onStart)
val currentOnStop by rememberUpdatedState(onStop)

// If `lifecycleOwner` changes, dispose and reset the effect
DisposableEffect(lifecycleOwner) {
    // Create an observer that triggers our remembered callbacks
    // for sending analytics events
    val observer = LifecycleEventObserver { _, event ->
        if (event == Lifecycle.Event.ON_START) {
            currentOnStart()
        } else if (event == Lifecycle.Event.ON_STOP) {
            currentOnStop()
        }
    }

    // Add the observer to the lifecycle
    lifecycleOwner.lifecycle.addObserver(observer)

    // When the effect leaves the Composition, remove the observer
    onDispose {
        lifecycleOwner.lifecycle.removeObserver(observer)
    }
}

/* Home screen content */

}


LaunchedEffect 内部开启了协程,并在退出组合时取消协程,DisposableEffect + rememberCoroutineScope 的方式可以模拟 LaunchedEffect,如下:



//LaunchedEffect
LaunchedEffect(key1 = Unit) {
}

//DisposableEffect + rememberCoroutineScope
val scope = rememberCoroutineScope()
DisposableEffect(key1 = Unit) {
val job = scope.launch { }
onDispose {
job.cancel()
}
}


#### rememberUpdatedState


LaunchedEffect(key) 会在key发生变化时会重启协程,如果不希望key变化时协程中断而是继续执行,可以通过 rememberUpdatedState 获取最新状态即可。



@Composable
fun rememberUpdatedState(newValue: T): State = remember {
mutableStateOf(newValue)
}.apply { value = newValue }

//MutableState
@Stable
interface MutableState : State {
override var value: T //rememberUpdatedState每次重组时都会对该值进行更新
operator fun component1(): T
operator fun component2(): (T) -> Unit
}


rememberUpdatedState 源码很简单,内部通过 remember + mutableStateOf 的方式,保证每次重组时都会将newValue 值进行更新到MutableState.value中,最终副作用里访问的也是最新的newValue了,从而实现副作用在不中断的前提下访问到最新传入的值。使用示例如下:



@Composable
fun LandingScreen(onTimeout: () -> Unit) {

// LandingScreen重组时会引用到最新的onTimeout函数
val currentOnTimeout by rememberUpdatedState(onTimeout)

// 如果发生重组,delay函数不会再次执行了;而currentOnTimeout却是最新的onTimeout函数。
LaunchedEffect(true) {
    delay(SplashWaitTimeMillis)
    currentOnTimeout()
}

/* Landing screen content */

}


#### SideEffect


SideEffect 在每次成功重组时都会执行,这么看好像SideEffect 并不能处理什么副作用呀。其实还是有点区别的,SideEffect只会在重组成功之后才会执行,如果重组失败,那么SideEffect中的lambda将不再执行,以免在当前组合操作失败时使对象处于不一致状态。


使用示例:



@Composable
fun SideEffectStudy() {
Log.e(“Tag”, “SideEffect launch”)
throw IllegalArgumentException(“exception throw”)
}


上述可组合项执行时会抛出异常,在抛异常之前会先输出Log。如果我们想重组成功之后再输出Log该怎么办呢?这时候就可以使用SideEffect了:



@Composable
fun SideEffectStudy() {
SideEffect {
Log.e(“Tag”, “SideEffect launch”)
}
throw IllegalArgumentException(“exception throw”)
}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数HarmonyOS鸿蒙开发工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年HarmonyOS鸿蒙开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
img

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新**

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
[外链图片转存中…(img-ODhV6a9s-1712848333464)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 18
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值