Stylianos Gakis
02/29/2024, 10:46 AMFatal Exception: java.lang.IndexOutOfBoundsException: index: 2, size: 2 with this snippet
val list: ImmutableList<Foo> = TODO() // from parameters
val pagerState = rememberPagerState(pageCount = { list.size })
HorizontalPager(
state = pagerState,
key = { index -> list[index].id },
) { page ->
Ui(page)
}
and the crash specifically happens on key = { index -> list[index].id },.
How would the key ever try to get an index that is not part of the list passed into the pagerState?
The only thing I can imagine happening is somehow the list being changed in a recomposition, the pagerState is updated, but the key function still is trying to for some reason fetch the item with the old index? I am asking here to see if anyone else has experienced this before.Zach Klippenstein (he/him) [MOD]
02/29/2024, 5:26 PMany possible scenario where you can imagine that this code would crashI can imagine a lot of things. Thereās one android version where some float functions just donāt work š
Zach Klippenstein (he/him) [MOD]
02/29/2024, 5:28 PMrememberPagerState will update the lambda passed to it on every recomposition, because the first composition will capture the initial list, and when the list changes Compose will create a new lambda, capture the new list, and pass it to rememberPagerState. In most composables, that is the expected behavior and the new lambda will be used. However, many times the parameters to remember* functions are only used to initialize the state, not keep it updated later, and that might be whatās happening here.Zach Klippenstein (he/him) [MOD]
02/29/2024, 5:28 PMval updatedList by rememberUpdatedState(list)
val pagerState = rememberPagerState(pageCount = { updatedList.size })Stylianos Gakis
03/11/2024, 9:02 AM@Composable
fun rememberPagerState(
initialPage: Int = 0,
initialPageOffsetFraction: Float = 0f,
pageCount: () -> Int
): PagerState {
return rememberSaveable(saver = PagerStateImpl.Saver) {
PagerStateImpl(
initialPage,
initialPageOffsetFraction,
pageCount
)
}.apply {
pageCountState.value = pageCount
}
}
So even if the āwrongā lambda is captured inside the rememberSaveable in there, which is definitely possible to happen, it looks like the pageCount lambda is being updated as it should even outside of the remember block.
The implementation is here https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/[ā¦]foundation/pager/PagerState.kt;l=110-117?q=rememberPagerState
So I think me doing it as well wouldnāt change something as far as I can tell.
Maaaybe this used to not be the same in older versions of the library which meant that it had the bug in the past but not anymore. I will just wait and see if I see this crash again I think now that I understand the potential problem a bit better.
Thanks for the help! šscana
04/08/2024, 11:07 AM