skip to Main Content

Issue appears on multiple screens. To my surprise the same code was working for previous versions of app. I just updated the compose libraries and then all this happening again and again on multiple locations.

I am using LazyColumn to populate list items. Whenever I try to scroll it, the App crashes. Below is the abstract code, that I’m using. The issue appears after updating compose Bom version to 2023-08-00. The same code works for other screens. The only difference here is that the lazy column item is almost half of the screen height(1:1 aspect ratio). So mostly two items per screen.

val users = viewModel.usersList

val lazyColumnListState = rememberLazyListState()

val shouldStartPaginate = remember {
    derivedStateOf {
        viewModel.canPaginate && (lazyColumnListState.layoutInfo.visibleItemsInfo.lastOrNull()?.index
            ?: -9) >= (lazyColumnListState.layoutInfo.totalItemsCount - 9)
    }
}

LaunchedEffect(key1 = shouldStartPaginate.value) {
    if (shouldStartPaginate.value && viewModel.listState == ListState.IDLE)
        viewModel.getMoreUsers()
}
//Inside Scafold
LazyColumn(
state = lazyColumnListState,
verticalArrangement = Arrangement.spacedBy(12.dp),
modifier = Modifier.padding(top = 16.dp)
) {
    items(
        items = users,
        key = { it.userID ?: (1000..5000).random() }) { i ->
        ComposeExploreItem(i)
    }


    if (users.isNotEmpty()) {
        item {
            Spacer(modifier = Modifier.height(40.dp))
        }
    }

    composeLazyColumnPagingLoader(
        viewModel.listState,
        users,
        "No users available"
    )
}

Here is the Crash Log.

java.lang.IllegalStateException: replace() called on item that was not placed
                                        at androidx.compose.ui.node.LayoutNodeLayoutDelegate$LookaheadPassDelegate.replace(LayoutNodeLayoutDelegate.kt:1517)
                                        at androidx.compose.ui.node.LayoutNode.lookaheadReplace$ui_release(LayoutNode.kt:926)
                                        at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:471)
                                        at androidx.compose.ui.node.MeasureAndLayoutDelegate.access$remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:39)
                                        at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout(MeasureAndLayoutDelegate.kt:352)
                                        at androidx.compose.ui.platform.AndroidComposeView.measureAndLayout(AndroidComposeView.android.kt:908)
                                        at androidx.compose.ui.node.Owner.measureAndLayout$default(Owner.kt:228)
                                        at androidx.compose.ui.platform.AndroidComposeView.dispatchDraw(AndroidComposeView.android.kt:1156)
                                        at android.view.View.draw(View.java:23269)
                                        at android.view.View.updateDisplayListIfDirty(View.java:22133)
                                        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4513)
                                        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4486)
                                        at android.view.View.updateDisplayListIfDirty(View.java:22089)
                                        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4513)
                                        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4486)
                                        at android.view.View.updateDisplayListIfDirty(View.java:22089)
                                        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4513)
                                        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4486)
                                        at android.view.View.updateDisplayListIfDirty(View.java:22089)
                                        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4513)
                                        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4486)
                                        at android.view.View.updateDisplayListIfDirty(View.java:22089)
                                        at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:689)
                                        at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:695)
                                        at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:793)
                                        at android.view.ViewRootImpl.draw(ViewRootImpl.java:4789)
                                        at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:4500)
                                        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3687)
                                        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2371)
                                        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9297)
                                        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1231)
                                        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1239)
                                        at android.view.Choreographer.doCallbacks(Choreographer.java:899)
                                        at android.view.Choreographer.doFrame(Choreographer.java:832)
                                        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1214)
                                        at android.os.Handler.handleCallback(Handler.java:942)
                                        at android.os.Handler.dispatchMessage(Handler.java:99)
                                        at android.os.Looper.loopOnce(Looper.java:201)
                                        at android.os.Looper.loop(Looper.java:288)
                                        at android.app.ActivityThread.main(ActivityThread.java:7918)
                                        at java.lang.reflect.Method.invoke(Native Method)
                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)

2

Answers


  1. While my solution isn’t relevant in the case of LazyColumn, the bug happens due to some already drawn composable being redrawn.

    In my case it happened due to me using HorizontalPager as in XML layouts ViewPager with very complex screen inside – so debugging became hell.

    It can be overcome by adding beyondBoundsPageCount with a value to your HorizontalPager because default value is 0!
    I’m not sure whether it’s an issue of Google Compose team or me doing something wrong but I’m sure the fix isn’t as straight forward as just updating a library (for me at least, I tried upgrading and downgrading multiple times and multiple possible libraries)

    Login or Signup to reply.
  2. While I do still not know the source of issue, I’ve found way to avoid the crash by wrapping your scrollable layout into ConstraintLayout

    such as
    ConstraintLayout(modifier = Modifier.fillMaxSize()) { LazyColumn(Modifier.constraintAs(...) {...}) {...} }

    Hope it helps.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search