Thread
#compose
    t

    tad

    1 year ago
    I think @Adam Powell might have something to say about this article: https://medium.com/google-developer-experts/jetpack-compose-missing-piece-to-the-mvi-puzzle-44c0e60b571
    (mainly the promotion of
    Flow.collectAsState
    for Compose UI state)
    Adam Powell

    Adam Powell

    1 year ago
    What about it?
    it's a direct translation of an existing pattern to use compose; I think the only thing I'd change about it would be to use a constant for the
    initial =
    value for
    collectAsState
    vs. constructing a new one to pass that gets discarded 🙂
    A few things about it I think nudge toward some additional/alternative tools as later steps, but ultimately they're optional. The nested
    .copy
    calls will start standing out next to other code that was simplified in the migration, and tools like arrow lenses or snapshot mutable state start to look compelling for addressing some of that
    ultimately compose is meant to be a toolkit rather than a framework; so long as you can BYO data, compose will present it for you without forcing major changes in your data modeling. Posts like this are success stories in that 🙂
    some of my more recent posts in this channel around
    collectAsState
    usage that nudge away from it are more around things that muddle the distinction between state and events, or that jump through a lot of hoops for creating different forms of derived state using StateFlows
    the mobius-style conventions on display in the linked post generally don't run into those issues
    t

    tad

    1 year ago
    Legit, thanks for this. I do still think snapshot state is the best option if your project is pure Compose, but I'll be a bit more thoughtful about alternative data patterns going forward.
    d

    dimsuz

    1 year ago
    I'd love to read something more on state vs events, separating what is state and what is event, I mean something about the way to think about this. I know now I have this separation in my head, after half a year ago I happened to have a conversation with Adam here and he suggested this separation of concepts: this really had shifted some gears into place for me 😃
    ppvi

    ppvi

    1 year ago
    we're working on official guidance
    Colton Idle

    Colton Idle

    1 year ago
    Awesome. Thanks Jose. That should be extremely useful. Especially curious about a hopefully simple way to send single events between VM and your composable/fragment. Using compose and representing state using snapshot state and not having to do the "backing property" pattern with LiveData is a breath of fresh air. Hope some similar simple pattern becomes popularized for events.
    ppvi

    ppvi

    1 year ago
    that's interesting. Backing properties are only needed in
    MutableLiveData
    or
    MutableStateFlow
    but most exposed state comes from another Flow anyway so they're the result of a
    combine
    ,
    flatMapLatest
    , etc. Are backing properties that common and annoying in your codebase that you want a completely different pattern? Could you be abusing the mutable data holders?
    Adam Powell

    Adam Powell

    1 year ago
    Yeah I'm curious to see some example code if you have some to share
    Colton Idle

    Colton Idle

    1 year ago
    Could you be abusing the mutable data holders?
    Most likely. Adam Powell once I'm back at my machine I will try to send something across. I think it's mostly due to different libraries that we've used in order to do this. We used to use the SingleLiveEvent from that article from Jose that was written a while back, and ever since we've been bouncing around different libraries.
    ppvi

    ppvi

    1 year ago
    to be clear: the single event thing is unrelated to the mutable data holders question
    Adam Powell

    Adam Powell

    1 year ago
    The best summary I know of so far is if your producer outlives your consumer you should produce state, not events. If your consumer outlives your producer you should usually produce events, and let the consumer own and aggregate state.
    Colton Idle

    Colton Idle

    1 year ago
    @Adam Powell ooh. That's a fairly nice way to put it.
    @ppvi oh boy. a lot of that went over my head. I just don't have a phd in coroutines, flows, channels etc so that stuff is scary. I guess I should just learn it one day. But overall it's just a lot to grok for just trying to send a signal from VM to my activity that a navigational event was triggered.
    Adam Powell

    Adam Powell

    1 year ago
    what the producer/consumer lifetime guideline says is that it's conceptually fraught to send events from a longer-lived producer to a shorter-lived consumer and working with state instead in those situations avoids a lot of downstream design considerations and edge cases to handle. It's a generalization of a lot of the underpinnings of compose's state hoisting patterns.
    the approach in your reddit comment above, @ppvi, is a conceptually sound way of solving the first step of a harder problem than I think is necessary to solve in these use cases
    ppvi

    ppvi

    1 year ago
    agreed
    d

    dimsuz

    1 year ago
    I wonder what are examples of events in Compose? It seems like there's state everywhere 🙂 Is "onClick" the event you are talking about?
    Adam Powell

    Adam Powell

    1 year ago
    it's an example of one, yes. The caller of a
    Button
    composable is the consumer by way of the
    onClick
    function passed as a parameter, and it outlives the
    Button
    itself (the event producer)
    Colton Idle

    Colton Idle

    1 year ago
    I guess I'm not seeing that as an event. For all events like onClick and onTextChange, I just have those as methods in my VM. For me the events are the ones that my VM has to emit to my activity so that it can perform some action, like navigation, or fire off an intent or something.
    Adam Powell

    Adam Powell

    1 year ago
    a method can be an event; that's exactly what things like
    View.OnClickListener#onClick
    are 🙂
    as your VM (assuming arch components VM) outlives your Activity, by the guideline above events from VM to Activity shouldn't exist at all, VM should only publish state to the Activity instead. The activity can observe the VM state and other states of its own and decide to navigate, startActivity, etc. in response - the event comes from a producer that doesn't outlive the activity - an observer of the VM state that doesn't outlive the VM either.
    Colton Idle

    Colton Idle

    1 year ago
    Interesting... So if I have single activity, multi fragments and each fragment is just a composable screen. I have one VM per fragment. In my fragments VM that's where a button click event would in turn emit an event to go to the next screen. So @Adam Powell you're saying that I should instead represent that as state?
    Adam Powell

    Adam Powell

    1 year ago
    that depends on what it actually represents
    based on the description there, there's a reasonable argument that the VM shouldn't be the authority in choosing to navigate to a next screen at all
    Colton Idle

    Colton Idle

    1 year ago
    Dang. And here I was thinking I had this whole thing pretty much figured out. I always considered that the "current screen" should just be a state that global to the app. Maybe something like that represented as state on the activity level would be more appropriate?
    t

    tad

    1 year ago
    unfortunately the state is not just "current screen" but also the back stack
    Adam Powell

    Adam Powell

    1 year ago
    the idea still works if you include the back stack in the idea of current navigational state
    different navigation models in android complicate things since you need an Activity to startActivity while correctly keeping your task intact, jetpack navigation needs the navigation controller which has similar scoping requirements
    but the jetpack navigation state (and your activity task state, for that matter) outlives the activity too
    the guideline above is still preserved: the activity/fragments/NavHost observe navigation state that outlives the activity, and you send events to it by way of navigateTo calls
    Colton Idle

    Colton Idle

    1 year ago
    Hm. Yeah I'm using Compose navigation. I guess I just have to figure out the "right" was to go from fragmentA to fragmentB. I'll read the docs again. Maybe I missed something.
    Adam Powell

    Adam Powell

    1 year ago
    it's just a generalization of state down/events up, but with definitions of "down" and "up" that speak to the associated scoping lifetimes rather than something strictly related to a UI tree
    Colton Idle

    Colton Idle

    1 year ago
    Yeah. To me it's just like. I'm using all jetpack AAC. Fragments. Nav. vM. Now I have fragment a and b. A has a button. That event of the button being clicked goes up to the VM. Now what. How do I go from a to b?
    Adam Powell

    Adam Powell

    1 year ago
    well, that's kinda the point. You sent a signal up to space instead of across the room on your local wifi network. 😛 Skip the detour/layover in the VM.
    Colton Idle

    Colton Idle

    1 year ago
    But what if the VM does some sort of validation on button press. I.e. is the form filled out? Yes? Send user to fragment b. If not, update the state with showErrorDialog = true or something.
    That should still surely go through the fragments VM?
    If not, then I'm missing something and idk how to android anymore and I officially resign. Lmao
    Adam Powell

    Adam Powell

    1 year ago
    if (vm.validate(info)) { navigator.navigateTo(next) }
    is still valid code but doesn't have to live in the vm itself, it can live in a place where both
    vm
    and
    navigator
    are in scope
    Colton Idle

    Colton Idle

    1 year ago
    Interesting. I feel like now I have business logic in my fragment then. But anyway. This definitely gives me something to think about. I'm going to read about plain compose with AAC nav because I'm curious how that'd work. I'm interested in ditching fragments and AAC VM entirely, but from what Ian said, it seems like it'd still be easier to do pure compose and keep AAC VM.
    Adam Powell

    Adam Powell

    1 year ago
    now I have business logic in my fragment then
    don't you have this where you wire up click handlers already?
    Colton Idle

    Colton Idle

    1 year ago
    I guess. I mean there has to be something concrete between the two. But yeah. Idk. Maybe I'm overthinking it. Maybe my brain is fried on this scorching Friday. Appreciate the help. May bounce a couple of things off of ya later. Really appreciate it though.