<@UPD4B2DNE> your droidcon online session today wa...
# compose
c
@Brian Gardner your droidcon online session today was really good and it has me excited!
l
Was it recorded? I have seen a ton of positive feedback about it and would love to check it out
c
@Leland Richardson [G] yep. Should be recorded and going onto droidcon videos soon. I'll ping ya if I see it. šŸ˜„
b
Thanks! I’m glad you liked it! I had a ton of fun with the session and I’m looking forward to making more video content soon
šŸ‘ 1
šŸ‘ 2
l
@Brian Gardner this was great. really nice intro for people. I’m a bit curious about the state issue you mentioned with AdapterList. Is this a known issue reported somewhere? cc @Ryan Mentley Also, i’m curious if you intentionally were saying to use
mutableStateOf(...)
where you used it instead of
state { ... }
. The latter seems more correct based on the usage.
r
Which state issue? Timecode?
b
l
in the video above, he is creating a toggleable button in each item of an adapterlist but said that it wasn’t updating when the state would get changed. My hunch is that the problem was actually just that mutableStateOf was being used instead of
state
though.
b
I likely wasn’t intentional about the state part. Why would the
mutableStateOf()
work differently than
state
?
l
mutableStateOf
is like a constructor, and will create a new instance each time (with the value you pass in). The
state
function is a composable function which will only execute the
init
lambda the first time, and it will remember the instance each time. when creating state ina composable function, this is usually what you want. it is basically shorthand for
remember { mutableStateOf(init()) }
r
The
mutableStateOf
in the preview, I think, is the one that probably should lost be
state
b
Ok, so creating the mutable state won’t trigger a recompose unless it’s wrapped in a
remember{}
block inside the composable function?
r
The code looks...otherwise mostly correct, but there's one suspicious bit. @Leland Richardson [G] is it valid to pass a
MutableState
directly like this? https://github.com/BrianGardnerAtl/JetpackComposePlayground/blob/adapter-list-state-spike/app/src/main/java/tech/briangardner/composeplayground/MainActivity.kt#L58
l
@Brian Gardner it does actually trigger an update… but when it recomposes the function, you just create a different mutable state instance (initialized to the same original value as before), so it doesn’t look like it’s doing anything
r
or should the value be passed directly?
l
it’s valid to do either
b
ah ok, I didn’t realize it was calling the composable function again to recreate the view. I wasn’t sure how the recompose step worked but that makes sense
r
alright, in that case that does look like it's probably an AdapterList bug, because the rest of the mutable state code outside of the preview looks correct
I'd have to debug it to be sure, though.
l
yeah it calls the function again. similar to react, flutter, etc, you want to write your composable functions as if they can be called ā€œagainā€ at any time, so if the function itself is introducing the state, you want to make sure and hold onto it properly (hence, use remember or state)
b
Another question I have is where it’s appropriate to create the state, since the functions can be called again. It seems like the state should be declared at the top-level, ā€˜screen’ component and passed down to the children. At least if the view state needs to change based on user interaction
l
there’s a whole can of worms that can be opened by that question… more or less, i try to think of it as create it in the place where the state is ā€œownedā€. That can be hard to define, but in general a good ā€œrule of thumbā€ first candidate is going to be the closest ancestor composable where the value is used entirely ā€œbelowā€ it, and nowhere else. If that scope changes, just move the state ā€œupā€ until it is satisfied again
but there’s a lot more that goes into it and i might give a different answer depending on the context.
for instance, if there’s some state variable like ā€œcurrent logged in userā€, that is going to be used at a much higher level than something more locally scoped or even just something less business-logic-specific and more ui-logic specific
b
That makes sense. The main scenario I think of is loading data from a database (or web server). I can setup the state when the data loads but when I need to modify the data based on the user interaction, how do I update the screen with the new data?
Assuming the ViewModel (or presenter) handles the data loading and updates, would I just create a new composable with the updated data or is there a better way to swap it out
l
in those cases i think the better thing is to use something other than state (like LiveData or Flow etc.) and then join that data into the composable hierarchy using state, but keep state as an implementation detail
you can see how this is done with some of our interop libraries with Rx and LiveData
b
Yeah, I saw that compose has the flow/rxjava to state stuff now which is cool. I’ll have to look into that more.
l
but in this case it is important to leverage tools such as
onCommit
to do it properly
also we will be releasing some new APIs around coroutines and such that will make a lot of this really really nice if your data layer uses suspend functions
b
Sweet! We’re definitely moving towards suspend functions for our data layers so that will be nice
l
nice
b
I haven’t messed with
onCommit
or
onActive
too much so I’ll look into those next
Thanks for talking through this stuff with me!
l
no problem!
thanks for creating such good content. it was a very well done live coding example
also, if you can, can you try updating your example to use
state
and see if that fixes the adapterlist bug you filed?
b
I’m glad you liked it! I can take some time tomorrow morning to rework my sample to see if using
state
works
l
awesome, thanks!