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