Would it be a feasible practice to pass a `Mutable...
# compose
d
Would it be a feasible practice to pass a
MutableSharedFlow
as a sort of event bus down the composable hierarchy that uses a sealed class with all possible actions callable on the viewModel, and then sending that in the top level composable? Or is it better to just stick to passing up all those onClicks as lambdas...?
k
Can you provide an example?
m
You could also just pass in a single lambda that accepts your actions instead of the state flow if that makes it easier to work with
d
How would that work? I need something like:
Copy code
sealed class Events {
  object Install : Events()
}

@Composable
fun InstallButton(eventBus: MutableSharedFlow<Events>) ...
   // in the button: onClick = { eventBus.value = Install) }
I have a bunch of these type of buttons, and I don't want to pass the viewModel to them, but on the other hand, trying to wire them all at the top level composable defeats the purpose of splitting them into separate composables....
k
I disagree with that, you're splitting them because you don't want to have a gigantic composable function with all your UI logic, I suggest you use lambdas for events. Also you mentioned that for the lambdas you'll have to still wire them to the ViewModel, I don't see how that is different for your event bus, it's true you'll be passing only one "event bus" but you still have to wire each event to its corresponding callback somewhere, likely in the ViewModel itself
m
Copy code
@Composable
fun InstallButton(onAction: (Events) -> Unit) {
    ...
    onClick = { onAction(Install) }
}
It just a tradeoff between passing in a lot of lambdas or switching on the event type in the view model. Just depends on what you think is easier. Neither is wrong imo but I’m open to reasons why one is better
d
I have a bunch of buttons that each have a string res id for the text and an action needing to be run on my view model, currently I have one generic button that takes a resId and an action, and the viewModel is plugging in the text and the action according to the current state. The same button can be displayed in many states, so I'd like to have a way to group the resId with the state and set them together when needed, also I thought that resIds are more the responsibility of the view than the viewModel... am I wrong?
k
You can keep your resource id in your state, and then load it with
stringResource
in Compose, as for the action (callback) I'll suggest you just store lambdas and wire them to your functions in your ViewModel or do it as Mike suggested with action identifiers and a single callback if you prefer that, now instead of storing a lambda you'd be storing the event identifier (e.g.
Install
). The "event bus" with a
MutableStateFlow
is kind of an overkill because you'll have to collect the flow to react to events.
d
Yeah, I agree about the overkill part of
MutableSharedFlow
... I guess Mike's suggestion is just a good. The viewModel is currently a BIG mess... I even tried grouping these buttons in
Copy code
// inside the viewModel... onInstall() being a function in it
val ActionButtons = object {
   val install = Pair(R.string.install, this::onInstall())
}
but for some reason
ActionButtons.install
is an unresolved function... so I thought to regroup them in the view code...
I guess I could always use a map... but with string keys 🙈... or to make an enum just for the keys...
Thanks for all the comments!