Compose + Coroutines
Launched Effect
println("recomposing hello button")
if(value % 3 ==0) {
Text(text = "can divide by 3")
LaunchedEffect(key1 = value){
try {
println("********************")
println("current thread : ${Thread.currentThread().name}")
withContext(Dispatchers.IO){
println("IO thread? : ${Thread.currentThread().name}")
}
delay(3000)
println("ending launched effect")
}catch (e:CancellationException){
println("******Launched effect was cancelled******")
}
}
}
similarly to :
val result=remember(key){calculate()}
"hacks/workarounds" already in official examples
@Composable
fun LandingScreen(modifier: Modifier = Modifier, onTimeout: () -> Unit) {
Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
// This will always refer to the latest onTimeout function that
// LandingScreen was recomposed with
val currentOnTimeout by rememberUpdatedState(onTimeout)
// Create an effect that matches the lifecycle of LandingScreen.
// If LandingScreen recomposes or onTimeout changes,
// the delay shouldn't start again.
LaunchedEffect(true) {
delay(SplashWaitTime)
currentOnTimeout()
}
Image(painterResource(id = R.drawable.ic_crane_drawer), contentDescription = null)
}
}
coroutine "problems"
LaunchedEffect(key1 = value){
try {
println("********************")
println("current thread : ${Thread.currentThread().name}")
withContext(Dispatchers.IO){
println("IO thread? : ${Thread.currentThread().name}")
Thread.sleep(3000)
}
println("ending launched effect")
}catch (e:CancellationException){
println("******Launched effect was cancelled******")
}
}
DisposableEffect?
DisposableEffect(key1 = value){
try {
println("********************")
println("current thread : ${Thread.currentThread().name}")
withContext(Dispatchers.IO){ // won't work
println("IO thread? : ${Thread.currentThread().name}")
delay(3000)
}
println("ending launched effect")
}catch (e:CancellationException){
println("******Launched effect was cancelled******")
}
onDispose { /**clean**/ }
}
// current thread : main !!!!
Coroutine outside compose
Wrong approach
val onClickProcedure: () -> Unit = {
LaunchedEffect(value){ //WONMT work!!
state.updateEvent(value + 1)
}
}
Button(onClick = onClickProcedure){
WhiteText("clicked $value times")
}
...........
val onClickProcedure: @Composable () -> Unit = { //Add @Composable
LaunchedEffect(value){
state.updateEvent(value + 1)
}
}
Button(onClick = onClickProcedure){ //error transfered here
WhiteText("clicked $value times")
}
Correct Approach
val onClickProcedure: () -> Unit = {
scope.launch(Dispatchers.IO) {
try{
withContext(Dispatchers.Main){
state.updateEvent(value + 1)
}
delay(2000)
println("*************Coroutine ended**************")
}catch (e:CancellationException){
println("*************Coroutine cancelled**************")
}
}
}
Button(onClick = onClickProcedure){
WhiteText("clicked $value times")
}
SharedFlow in compose
val flow = MutableSharedFlow<Int>()
@Composable
fun FlowExperiment1(){
val scope = rememberCoroutineScope()
LaunchedEffect(true){
scope.launch(Dispatchers.IO) {
(1 .. 50).forEach{
println("emiting $it")
flow.emit(it)
delay(50)
}
}
}
val flowValue by flow.collectAsState(initial = 0)
Text("received $flowValue")
}
Last updated
Was this helpful?