https://kotlinlang.org logo
#compose
Title
# compose
p

Patrick Steiger

10/03/2023, 10:57 PM
So, it seems that passing lambdas that capture a
CoroutineScope
to composables will cause composables to never skip recompositions since
CoroutineScope
is unstable. Is there a recommended pattern here? Remembering all the lambdas is just awkward
Creating a
Copy code
@Immutable 
class StableCoroutineScope(
  scope: CoroutineScope
): CoroutineScope by scope 

@Composable
fun rememberStableCoroutineScope(): StableCoroutineScope {
  val scope = rememberCoroutineScope()
  return remember(scope) {
    StableCoroutineScope(scope)
  }
}
Works to avoid recompositions, but feels weird (and I’m not 100% sure on the correctness of the Immutable annotation in this context since the coroutineContext elements are potentially mutable themselves, although I don’t think that e.g mutating
Job
state matters for recompositions)
a

ascii

10/04/2023, 2:18 AM
@Stable/@Immutable
are mostly to bridge the gap between Compose compiler & whatever lies outside its vision. While there are valid cases to force something you know to be stable, it just makes testing harder. What does the lambda do exactly? Maybe it can be done some other way, e.g. LaunchedEffect.
p

Patrick Steiger

10/04/2023, 2:39 AM
@ascii event callback that launches a coroutine . E.g
Copy code
onClick = {
  scope.launch { 
    flow.emit(Something)
  }
}
a

ascii

10/04/2023, 2:48 AM
I have something similar for analytics. Instead of emitting immediately, I collect them and flush per x items via
LaunchedEffect(sink.size)
. Otherwise I'd just do
remember(scope)
everywhere. Won't bother with wrapping it.
z

Zach Klippenstein (he/him) [MOD]

10/04/2023, 4:20 PM
For that specific example, can you use an emit method that doesn’t require suspending? Eg
tryEmit
exists on some flows
p

Patrick Steiger

10/04/2023, 4:37 PM
Yes, I can, but if I want tryEmit to never fail I’d need an unlimited buffer, and perhaps I would rather not have an unlimited buffer flow. I mean, if I call emit, and buffer is full, and coroutine suspends, and composable leaves composition, and scope is cancelled, maybe I want to “lose” that event, which is something that would not happen with unlimited buffer flow So tryEmit would have a bit different semantics in there.
👍🏻 1