Travis Griggs
04/18/2023, 7:13 PMStylianos Gakis
04/18/2023, 9:14 PMcurrentTimeAsState
can this way configure their own preferred update interval, and it stops ticking when not in composition too. If this is not what you are looking for, I’d be interested to hear what you need instead.Travis Griggs
04/19/2023, 7:08 PMStylianos Gakis
04/19/2023, 8:29 PMTravis Griggs
04/19/2023, 8:29 PMval currentTime = CurrentTimeAsState()
val remaining: Duration by remember { derivedStateOf { active.interval.endInclusive - currentTime.value } }
Text(text = "$remaining" ... )
Is that how you use it?Stylianos Gakis
04/19/2023, 8:32 PMendInclusive
is, and if that is also mutablestate or not, and if active
is a parameter that may also change. If you showed me the entire function I might be able to give better help. But the idea is that if active.interval.endinclusive
is not mutable state, and it’s a parameter which may change, you may need to add it as a key in your remember
call, so you never reference an old endInclusive
value.Travis Griggs
04/19/2023, 9:01 PM@Composable
private fun ActiveIntervalRow(
active: ValveActive, isLocked: Boolean, modifier: Modifier = Modifier
) {
val boldColor = isLocked.opt(Color(0.8f, 0.8f, 0.8f), active.darkColor)
val softColor: Color = isLocked.opt(Color.Transparent, active.color.copy(alpha = 0.3f))
Row(
modifier = modifier.background(color = softColor),
verticalAlignment = Alignment.CenterVertically
) {
val currentTime = CurrentTimeAsState()
val into: Duration by remember { derivedStateOf { active.interval.start - currentTime.value } }
Text(
text = into.clockString,
modifier = Modifier.padding(start = 12.dp),
color = boldColor,
fontSize = 12.sp,
fontFamily = FontFamily(Typeface.MONOSPACE)
)
Box(
modifier = Modifier
.fillMaxHeight()
.weight(1f)
.padding(6.dp)
) {
Box(
modifier = Modifier
.background(color = boldColor)
.align(Alignment.Center)
.fillMaxWidth()
.height(1.5.dp)
)
Box(
modifier = Modifier
.background(color = boldColor)
.align(Alignment.CenterStart)
.fillMaxWidth(fraction = active.fraction)
.height(5.5.dp)
)
}
val remaining: Duration by remember { derivedStateOf { active.interval.endInclusive - currentTime.value } }
Text(
text = remaining.clockString,
modifier = Modifier.padding(end = 12.dp),
color = boldColor,
fontSize = 11.sp,
fontFamily = FontFamily(Typeface.MONOSPACE)
)
}
}
Travis Griggs
04/19/2023, 9:02 PMStylianos Gakis
04/19/2023, 9:05 PMUnit
aka composables that do not emit UI is defined here https://github.com/androidx/androidx/blob/androidx-main/compose/docs/compose-api-guidelines.md#naming-composable-functions-that-return-values
This entire document in fact is super interesting, so I suggest you do read through all of it at least once
A function named CurrentTimeAsState
implies that there is some UI that is being generated from this, but this is a lie, since it returns a value instead. It’s very odd looking inside compose code, and I would very strongly suggest you do not do it, to make it easier for other compose devs to better understand your code 😊Stylianos Gakis
04/19/2023, 9:10 PMValveActive
internally stores start
as mutableState, then this is fine.
If not, you’d want to add active
as a key to your remember, like
val into: Duration by remember(active.interval.start) { derivedStateOf { active.interval.start - currentTime.value } }
Since if you do not do that, if active
changes, this calculation will not be recalculated, as it wouldn’t know to do so. It does when reading currentTime
since derivedStateOf
does that automatically when specifically reading state stored inside compose runtime’s MutableState.
And then val remaining: Duration by remember(active.interval.endInclusive) { derivedStateOf { active.interval.endInclusive - currentTime.value } }
too, for the second usage of this
My general rule of thumb when deciding on what to put in the keys of a remember, is
• what am I reading from inside my remember lambda?
• Are any of those things gonna ever change? If they are parameters in the composable then that’s a yes, so that’s an easy inclusion
• Are they MutableState? If yes, can I use derivedStateOf to avoid adding that key instead?
Something like that 😅Travis Griggs
04/19/2023, 9:23 PMTravis Griggs
04/19/2023, 9:24 PMStylianos Gakis
04/19/2023, 9:27 PMActiveIntervalRow
function, active
is a normal parameter, not mutable state.
Look at this discussion https://kotlinlang.slack.com/archives/CJLTWPH7S/p1640285517040200?thread_ts=1640270959.029600&cid=CJLTWPH7S for some very good explanation on this, and some extra interesting information too.Travis Griggs
04/19/2023, 9:27 PMStylianos Gakis
04/19/2023, 9:30 PMcurrentTimeAsState
you could definitely get things updating in different frames. But tbh it sounds like the solution there is to lift that function to the lowest common parent, and drill that one down to the functions that need it.
Now if your application somehow uses this so much that you need to read this virtually everywhere, maybe a composition local would be good, but I really would be careful with making unnecessary composition locals whenever possible.Travis Griggs
04/19/2023, 9:31 PMTravis Griggs
04/19/2023, 9:35 PMStylianos Gakis
04/19/2023, 9:38 PMTravis Griggs
04/19/2023, 9:40 PMStylianos Gakis
04/19/2023, 9:40 PMFoo
then it will in fact recompose all the way down. But if you pass it down as () -> Foo
then it won’t and it will only recompose inside the composition scopes that the state is read. More on this in the aforementioned article, and even some mention of it here.Stylianos Gakis
04/19/2023, 9:44 PM() -> Foo
can go around that.
Oh and speaking of that, this article https://dev.to/zachklipp/scoped-recomposition-jetpack-compose-what-happens-when-state-changes-l78 is also a must read IMO if you want to understand how all this works. This is maybe a pre-requisite to reading the donut hole skipping article. As it goes through a lot of the other concepts important to compose and recomposition scopesStylianos Gakis
04/19/2023, 9:45 PMTravis Griggs
04/19/2023, 9:46 PMTravis Griggs
04/19/2023, 9:47 PMStylianos Gakis
04/19/2023, 9:48 PMTravis Griggs
04/21/2023, 8:20 PMStylianos Gakis
04/21/2023, 8:22 PM