Сбой Android-приложения из-за исключения NullPointerException в сопровождении HorizontalPager for Jetpack Compose
Я использую Performpanist HorizontalPager в проекте Android Jetpack Compose, чтобы показать динамически изменяющийся список из Firebase Firestore. Он работает хорошо, если список изначально пуст или содержит элементы, но как только в нем есть элементы, а затем он становится пустым, приложение вылетает из-за исключения NullPointerException из HorizontalPager.
Ниже приведены соответствующие зависимости.
compose_version = '1.0.1'
hilt_version = '2.38.1'
kotlin_version = '1.5.21'
// Accompanist
def accompanistVersion = "0.16.1"
implementation("com.google.accompanist:accompanist-pager:$accompanistVersion")
implementation("com.google.accompanist:accompanist-pager-indicators:$accompanistVersion")
implementation("com.google.accompanist:accompanist-systemuicontroller:$accompanistVersion")
implementation("com.google.accompanist:accompanist-insets:$accompanistVersion")
implementation("com.google.accompanist:accompanist-flowlayout:$accompanistVersion")
implementation("com.google.accompanist:accompanist-swiperefresh:$accompanistVersion")
def coil = "1.3.2"
implementation("io.coil-kt:coil:$coil")
implementation("io.coil-kt:coil-compose:$coil")
Ниже приведен фрагмент кода.
val pagerList: List<PagerDomain> by viewModel.pagerList.collectAsState()
val pagerState: PagerState = rememberPagerState(pageCount = pagerList.size)
Column(
modifier = Modifier
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Bottom
) {
HorizontalPager(
modifier = Modifier
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
state = pagerState,
) { page: Int ->
ProfileCarouselItem(
modifier = Modifier
.graphicsLayer {
// Calculate the absolute offset for the current page from the
// scroll position. We use the absolute value which allows us to mirror
// any effects for both directions
val pageOffset =
calculateCurrentOffsetForPage(page).absoluteValue
// We animate the scaleX + scaleY, between 85% and 100%
lerp(
start = 0.85f,
stop = 1f,
fraction = 1f - pageOffset.coerceIn(0f, 1f)
).also { scale ->
scaleX = scale
scaleY = scale
}
// We animate the alpha, between 50% and 100%
alpha = lerp(
start = 0.5f,
stop = 1f,
fraction = 1f - pageOffset.coerceIn(0f, 1f)
)
}
.fillMaxWidth(0.8f)
.aspectRatio(0.5f),
pagerDomain = pagerList[page],
onConnectClick = onConnectClick,
showConnectLoading = showConnectLoading
)
}
HorizontalPagerIndicator(
pagerState = pagerState,
modifier = Modifier
.padding(16.dp),
)
}
Ниже представлена трассировка стека.
Fatal Exception: java.lang.NullPointerException
com.google.accompanist.pager.PagerState.getCurrentPageOffset (PagerState.kt:745)
com.google.accompanist.pager.PagerIndicatorKt$HorizontalPagerIndicator$1$2$1.invoke-Bjo55l4 (PagerIndicator.kt:95)
com.google.accompanist.pager.PagerIndicatorKt$HorizontalPagerIndicator$1$2$1.invoke (PagerIndicator.kt:94)
androidx.compose.foundation.layout.OffsetPxModifier$measure$1.invoke (Offset.kt:202)
androidx.compose.foundation.layout.OffsetPxModifier$measure$1.invoke (Offset.kt:201)
androidx.compose.ui.layout.MeasureScope$layout$1.placeChildren (MeasureScope.kt:68)
androidx.compose.ui.node.DelegatingLayoutNodeWrapper.placeAt-f8xVGno (DelegatingLayoutNodeWrapper.kt:111)
androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno (Placeable.kt:31)
androidx.compose.ui.layout.Placeable$PlacementScope.place-70tqf50 (Placeable.kt:370)
androidx.compose.ui.node.OuterMeasurablePlaceable.placeAt-f8xVGno (OuterMeasurablePlaceable.kt:149)
androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno (Placeable.kt:31)
androidx.compose.ui.layout.Placeable$PlacementScope.place-70tqf50 (Placeable.kt:370)
androidx.compose.ui.layout.Placeable$PlacementScope.place-70tqf50$default (Placeable.kt:203)
androidx.compose.foundation.layout.BoxKt.placeInBox (Box.kt:186)
androidx.compose.foundation.layout.BoxKt.access$placeInBox (Box.kt:1)
androidx.compose.foundation.layout.BoxKt$boxMeasurePolicy$1$measure$5.invoke (Box.kt:167)
androidx.compose.foundation.layout.BoxKt$boxMeasurePolicy$1$measure$5.invoke (Box.kt:163)
androidx.compose.ui.layout.MeasureScope$layout$1.placeChildren (MeasureScope.kt:68)
androidx.compose.ui.node.LayoutNode$layoutChildren$1.invoke (LayoutNode.kt:925)
androidx.compose.ui.node.LayoutNode$layoutChildren$1.invoke (LayoutNode.kt:915)
androidx.compose.runtime.snapshots.Snapshot$Companion.observe (Snapshot.kt:1776)
androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads (SnapshotStateObserver.kt:123)
androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release (OwnerSnapshotObserver.kt:75)
androidx.compose.ui.node.OwnerSnapshotObserver.observeLayoutSnapshotReads$ui_release (OwnerSnapshotObserver.kt:56)
androidx.compose.ui.node.LayoutNode.layoutChildren$ui_release (LayoutNode.kt:915)
androidx.compose.ui.node.LayoutNode.onNodePlaced$ui_release (LayoutNode.kt:901)
androidx.compose.ui.node.InnerPlaceable.placeAt-f8xVGno (InnerPlaceable.kt:94)
androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno (Placeable.kt:31)
androidx.compose.ui.layout.Placeable$PlacementScope.placeRelative (Placeable.kt:359)
androidx.compose.ui.layout.Placeable$PlacementScope.placeRelative$default (Placeable.kt:179)
androidx.compose.foundation.layout.PaddingModifier$measure$1.invoke (Padding.kt:370)
androidx.compose.foundation.layout.PaddingModifier$measure$1.invoke (Padding.kt:368)
androidx.compose.ui.layout.MeasureScope$layout$1.placeChildren (MeasureScope.kt:68)
androidx.compose.ui.node.DelegatingLayoutNodeWrapper.placeAt-f8xVGno (DelegatingLayoutNodeWrapper.kt:111)
androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno (Placeable.kt:31)
androidx.compose.ui.layout.Placeable$PlacementScope.place-70tqf50 (Placeable.kt:370)
androidx.compose.ui.node.OuterMeasurablePlaceable.placeAt-f8xVGno (OuterMeasurablePlaceable.kt:149)
androidx.compose.ui.node.OuterMeasurablePlaceable.replace (OuterMeasurablePlaceable.kt:161)
androidx.compose.ui.node.LayoutNode.replace$ui_release (LayoutNode.kt:811)
androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout (MeasureAndLayoutDelegate.kt:215)
androidx.compose.ui.platform.AndroidComposeView.measureAndLayout (AndroidComposeView.android.kt:510)
androidx.compose.ui.platform.AndroidComposeView.dispatchDraw (AndroidComposeView.android.kt:666)
android.view.View.draw (View.java:23904)
android.view.View.updateDisplayListIfDirty (View.java:22776)
android.view.ViewGroup.recreateChildDisplayList (ViewGroup.java:5320)
android.view.ViewGroup.dispatchGetDisplayList (ViewGroup.java:5292)
android.view.View.updateDisplayListIfDirty (View.java:22731)
android.view.ViewGroup.recreateChildDisplayList (ViewGroup.java:5320)
android.view.ViewGroup.dispatchGetDisplayList (ViewGroup.java:5292)
android.view.View.updateDisplayListIfDirty (View.java:22731)
android.view.ViewGroup.recreateChildDisplayList (ViewGroup.java:5320)
android.view.ViewGroup.dispatchGetDisplayList (ViewGroup.java:5292)
android.view.View.updateDisplayListIfDirty (View.java:22731)
android.view.ViewGroup.recreateChildDisplayList (ViewGroup.java:5320)
android.view.ViewGroup.dispatchGetDisplayList (ViewGroup.java:5292)
android.view.View.updateDisplayListIfDirty (View.java:22731)
android.view.ThreadedRenderer.updateViewTreeDisplayList (ThreadedRenderer.java:579)
android.view.ThreadedRenderer.updateRootDisplayList (ThreadedRenderer.java:585)
android.view.ThreadedRenderer.draw (ThreadedRenderer.java:662)
android.view.ViewRootImpl.draw (ViewRootImpl.java:5042)
android.view.ViewRootImpl.performDraw (ViewRootImpl.java:4749)
android.view.ViewRootImpl.performTraversals (ViewRootImpl.java:3866)
android.view.ViewRootImpl.doTraversal (ViewRootImpl.java:2618)
android.view.ViewRootImpl$TraversalRunnable.run (ViewRootImpl.java:9965)
android.view.Choreographer$CallbackRecord.run (Choreographer.java:1010)
android.view.Choreographer.doCallbacks (Choreographer.java:809)
android.view.Choreographer.doFrame (Choreographer.java:744)
android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:995)
android.os.Handler.handleCallback (Handler.java:938)
android.os.Handler.dispatchMessage (Handler.java:99)
android.os.Looper.loop (Looper.java:246)
android.app.ActivityThread.main (ActivityThread.java:8506)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:602)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1130)
1 ответ
Первый сбой в вашем коде - это результат ошибки аккомпаниатора . Пока это не исправлено, вам просто нужно обернуть
HorizontalPagerIndicator
с
if
:
if (pagerState.pageCount != 0) {
HorizontalPagerIndicator(
pagerState = pagerState,
modifier = Modifier
.padding(16.dp),
)
}
После того, как вы исправите этот сбой, вы столкнетесь с другим. Это происходит потому что ты звонишь
calculateCurrentOffsetForPage
внутри
graphicsLayer
, который вызывается после
pagerList
изменять
Вы можете легко решить эту проблему, убрав этот расчет из модификатора:
// Calculate the absolute offset for the current page from the
// scroll position. We use the absolute value which allows us to mirror
// any effects for both directions
val pageOffset = calculateCurrentOffsetForPage(page).absoluteValue
ProfileCarouselItem(
modifier = Modifier
.graphicsLayer {
// We animate the scaleX + scaleY, between 85% and 100%
lerp(
start = 0.85f,
stop = 1f,
fraction = 1f - pageOffset.coerceIn(0f, 1f)
).also { scale ->
scaleX = scale
scaleY = scale
}
// We animate the alpha, between 50% and 100%
alpha = lerp(
start = 0.5f,
stop = 1f,
fraction = 1f - pageOffset.coerceIn(0f, 1f)
)
}
...
)