u

    ursus

    1 year ago
    silly question does compose render after
    Activity.onStop
    ?
    Zach Klippenstein (he/him) [MOD]

    Zach Klippenstein (he/him) [MOD]

    1 year ago
    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

    ursus

    1 year ago
    why is that the default? to keep symmetry with Activity?
    Adam Powell

    Adam Powell

    1 year ago
    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

    ursus

    1 year ago
    I see so what zach said is not really correct, right? Views are not detached after hitting the home button
    Adam Powell

    Adam Powell

    1 year ago
    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

    ursus

    1 year ago
    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
    Zach Klippenstein (he/him) [MOD]

    Zach Klippenstein (he/him) [MOD]

    1 year ago
    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 Flows, 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.
    Adam Powell

    Adam Powell

    1 year ago
    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
    Zach Klippenstein (he/him) [MOD]

    Zach Klippenstein (he/him) [MOD]

    1 year ago
    closes laptop and goes to make more coffee, clearly brain not working yet
    u

    ursus

    1 year ago
    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!
    Adam Powell

    Adam Powell

    1 year ago
    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"...
    Zach Klippenstein (he/him) [MOD]

    Zach Klippenstein (he/him) [MOD]

    1 year ago
    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.
    Adam Powell

    Adam Powell

    1 year ago
    Me too. Ideally we'll deprecate it with the introduction of these newer APIs
    u

    ursus

    1 year ago
    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
    Adam Powell

    Adam Powell

    1 year ago
    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

    ursus

    1 year ago
    yea..I only tend to make the top-most upstreams like data sync constrained to app being in foreground
    appInForeground
    .flatMapLatest {
       if (!it) emptyFlow() else doStuff()
    }
    this pattern should get promoted more, really handy
    Adam Powell

    Adam Powell

    1 year ago
    That's in essence what the new
    flowOnLifecycle
    operator does 🙂
    So as for promoting it more, we're on it 👍