silly question does compose render after `Activit...
# compose
u
silly question does compose render after
Activity.onStop
?
z
I believe Compose stops rendering for good when the
Composition
is disposed, so the answer depends on your ViewCompositionStrategy – the default will dispose the composition when the view is detached, but there’s another strategy that waits until the lifecycle is destroyed. Edit: added “for good” – the dispatcher will pause in certain lifecycle states, which effectively stops rendering, see thread below.
u
why is that the default? to keep symmetry with Activity?
a
If you're using the default Recomposer that gets configured when you use ComposeView or ComponentActivity.setContent then recompositions will stop when the lifecycle does and start again when the lifecycle does.
Same with any compose driven animations; the animation won't perform work for new frames while the host lifecycle is stopped
u
I see so what zach said is not really correct, right? Views are not detached after hitting the home button
a
The same mechanism is used for both as it's driven by the
withFrameNanos
API; the underlying
MonotonicFrameClock
pauses while the lifecycle is stopped.
He's right too, there are just several mechanisms in play.
What Zach said is what makes it safe to detach a ComposeView and leave it for the GC to collect by default
But you are right, views aren't detached if you hit the home button, or if another activity starts on top of the current one
u
what im basically asking is, I used to subscribe viewmodel.state observable between activity.onStart and onStop; so if viewmodel state changed while in background, view wont get rerendered do I need to pass in this start-stop lifecycle explicitly somewhere now, or does compose make this judgement implicitly
z
if viewmodel state changed while in background, view wont get rerendered
I think so, based on what Adam is saying. IIUC because the dispatcher is paused, if you’re using `Flow`s, the flow will effectively experience backpressure when you emit while collector is paused. So the “correct” behavior could depend on your
ViewModel
implementation – if the subscription represents some expensive resource, it might make more sense to unsubscribe/stop collecting entirely when the view won’t be updated. But if it’s just backed by something cheap like a
MutableStateFlow
then allowing the subscription to persist and just not update the view might be ok.
a
Compose doesn't know what you want in that case. The flow you collect won't be backpressured, it will still keep updating the underlying data. Compose won't act on that data changing while the activity is stopped.
Two new APIs over in lifecycle-ktx are probably helpful for this case though,
.flowWithLifecycle
, which will stop and restart collection of an upstream flow while a lifecycle is below a given state, and
repeatOnLifecycle
, which can be used inside LaunchedEffect or elsewhere
🎉 1
z
closes laptop and goes to make more coffee, clearly brain not working yet
😄 1
1
u
yes I want to keep updating viewmodel state but view should ignore it while out of lifecycle. and when lifecycle gained, it should render the latest viewmodel state blockingly (mutableStateFlow) so it does that out of the box, thanks!
a
These APIs are meant to replace the pausing coroutine dispatcher in lifecycle-ktx, which would result in backpressured flow collections but also caused a lot of other hard to predict behavior, bugs, arbitrarily delayed cancellation and exception handling, long memory "leaks"...
z
These APIs are meant to replace the pausing coroutine dispatcher in lifecycle-ktx,
Ah, I thought they were built on top of this dispatcher. Thank god, that thing creeped me out.
a
Me too. Ideally we'll deprecate it with the introduction of these newer APIs
🙏 2
u
but thats meant for some heavy processing like camera and stuff like that, right? regular crud screen just wants to not render while on bg since nobody sees that, upstream doing stuff is cheap so it doesnt matter and it does that out of the box so great
a
It does do what you're describing out of the box, but the assertion that upstream doing stuff is cheap and so you can leave it running while activities are stopped is exactly why OEMs do the things that dontkillmyapp.com talks about 🙂
Just be careful about what gets left running is all
u
yea..I only tend to make the top-most upstreams like data sync constrained to app being in foreground
Copy code
appInForeground
.flatMapLatest {
   if (!it) emptyFlow() else doStuff()
}
this pattern should get promoted more, really handy
a
That's in essence what the new
flowOnLifecycle
operator does 🙂
So as for promoting it more, we're on it 👍
👍 1