Of late, I've been getting intermittent crashes wh...
# compose-android
t
Of late, I've been getting intermittent crashes whose trace looks like:
Copy code
FATAL EXCEPTION: main
Process: com.nelsonirrigation.twigmc.next, PID: 16234
java.lang.IndexOutOfBoundsException: Index 76, size 76
at androidx.compose.foundation.lazy.layout.MutableIntervalList.checkIndexBounds(IntervalList.kt:183)
at androidx.compose.foundation.lazy.layout.MutableIntervalList.get(IntervalList.kt:166)
at androidx.compose.foundation.lazy.layout.LazyLayoutIntervalContent.getKey(LazyLayoutIntervalContent.kt:86)
at androidx.compose.foundation.lazy.LazyListItemProviderImpl.getKey(LazyListItemProvider.kt:85)
at androidx.compose.foundation.lazy.layout.LazyLayoutMeasureScopeImpl.measure-0kLqBqw(LazyLayoutMeasureScope.kt:122)
at androidx.compose.foundation.lazy.LazyListMeasuredItemProvider.getAndMeasure(LazyListMeasuredItemProvider.kt:48)
at androidx.compose.foundation.lazy.LazyListMeasureKt.measureLazyList-5IMabDg(LazyListMeasure.kt:195)
at androidx.compose.foundation.lazy.LazyListMeasuredItemProvider.getAndMeasure(LazyListMeasuredItemProvider.kt:48)
at androidx.compose.foundation.lazy.LazyListMeasureKt.measureLazyList-5IMabDg(LazyListMeasure.kt:195)
at androidx.compose.foundation.lazy.LazyListKt$rememberLazyListMeasurePolicy$1$1.invoke-0kLqBqw(LazyList.kt:313)
at androidx.compose.foundation.lazy.LazyListKt$rememberLazyListMeasurePolicy$1$1.invoke(LazyList.kt:178)
Any suggestions on how to avoid this? What I might be doing to cause it? The trace goes quite a ways back before I see any of my own code :(
s
It is usually caused by the fact that your data set was updated from bg thread during a measure pass, and Compose still thinks that there's 76 items on the list while its size was reduced
Ideally, we would run measure and layout in separate snapshots, so it would be consistent throughout the pass, but that breaks some existing code, unfortunately. What you can do is make sure that the state that is used in
items
is only updated on the main thread.
s
Can you confirm that Travis, are you perhaps changing something from inside your VM directly? Also Andrei, if we were setting it from a coroutine, Dispatcher.Main and Dispatcher.Main.immediate should both work to avoid this bug right?
s
Yeah, just collecting on the right dispatcher should do it
thank you color 1
t
Yeah, I've got mutableStates being updated by an IO Dispatcher. I didn't realize this was/is a no-no. I'll change that (for now) and see if that quits happening.
s
Yeah, technically it is supported for most things that are run in composition, lazy lists are just slightly more complicated here
t
It's a little more complicated I realize now. The LazyColumn is actually taking its items from a derivedState, which computes based on some mutableStates from a repo that are being updated by an IO process. Is there a way to make the derivation computation/update from a derivedState run on the correct thread so compose doesn't have issues?
s
mmh, don't think so,
derivedStateOf
is practically just a lambda with a cache.
You can use this hack on lazy column to force snapshot isolation on measure:
Copy code
Modifier.layout { m, c ->
  val placeable = Snapshot.withMutableSnapshot { m.measure(c) }
  layout(placeable.width, placeable.height) { placeable.place(IntOffset.Zero) }
}
🙏 1
🪄 1
c
oh wow. yeah I'm with travis. i didn't know i should be switching dispatchers to set the data. 🤯
s
It is more of a bug than a requirement tbf
đź‘€ 1
t
I’ve created a ThreadSafeLazyColumn wrapper for LazyColumn that applies Andrei’s “workaround” to the modifier. I’m happy. It doesn’t blow up anymore.
K 2