无法在本地重现,在 firebase 上看到多次崩溃。它似乎对不同设备和 Android 版本的不同用户产生一致的影响。
堆栈跟踪没有给出任何迹象表明这是我们组件的问题,除了动画的持续时间之外,我尝试进行一些挖掘但无法重现。
下面是组件上类似编码的代码部分,我们在其中找到了崩溃时的 anaimationDuration 值:
@Composable
fun SomeComposable(
someData: SomeData,
modifier: Modifier = Modifier
) {
AnimatedVisibility(
modifier = modifier,
visible = ...
) {
val progressValue = remember(someData) {
(someData.value1.toFloat() / someData.value2.toFloat()) * 100
}
val someDataAnimation by animateFloatAsState(
targetValue = progressValue,
animationSpec = tween(
durationMillis = 700 <- duration value from a stacktrace
)
)
val angle = remember(someDataAnimation) {
someDataAnimation * 360 / 100
}
Box(...) {
Canvas(...) {
drawArc(
...,
sweepAngle = angle,
...
)
}
}
}
}
堆栈跟踪:
java.lang.IllegalStateException: AnimationVector cannot contain a NaN. AnimationVector1D: value = NaN. Animation: TargetBasedAnimation: NaN -> 41.12,initial velocity: AnimationVector1D: value = 0.0, duration: 700 ms,animationSpec: androidx.compose.animation.core.VectorizedTweenSpec@3d4a9b6, playTimeNanos: 0
androidx.compose.animation.core.TargetBasedAnimation.getValueFromNanos(Animation.kt:242)
androidx.compose.animation.core.SuspendAnimationKt.animate(SuspendAnimation.kt:233)
androidx.compose.animation.core.Animatable$runAnimation$2.invokeSuspend(Animatable.kt:305)
androidx.compose.animation.core.Animatable$runAnimation$2.invoke(:8)
androidx.compose.animation.core.Animatable$runAnimation$2.invoke(:2)
androidx.compose.animation.core.MutatorMutex$mutate$2.invokeSuspend(InternalMutatorMutex.kt:119)
androidx.compose.animation.core.MutatorMutex$mutate$2.invoke(:8)
androidx.compose.animation.core.MutatorMutex$mutate$2.invoke(:4)
kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:89)
kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:264)
androidx.compose.animation.core.MutatorMutex.mutate(InternalMutatorMutex.kt:112)
androidx.compose.animation.core.MutatorMutex.mutate$default(InternalMutatorMutex.kt:109)
androidx.compose.animation.core.Animatable.runAnimation(Animatable.kt:295)
androidx.compose.animation.core.Animatable.animateTo(Animatable.kt:238)
androidx.compose.animation.core.Animatable.animateTo$default(Animatable.kt:225)
androidx.compose.animation.core.AnimateAsStateKt$animateValueAsState$3$1.invokeSuspend(AnimateAsState.kt:426)
kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch(AndroidUiDispatcher.android.kt:81)
androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch(AndroidUiDispatcher.android.kt:41)
androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.run(AndroidUiDispatcher.android.kt:57)
android.os.Handler.handleCallback(Handler.java:942)
android.os.Handler.dispatchMessage(Handler.java:99)
android.os.Looper.loopOnce(Looper.java:226)
android.os.Looper.loop(Looper.java:313)
android.app.ActivityThread.main(ActivityThread.java:8757)
java.lang.reflect.Method.invoke(Method.java:0)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
版本:
Jetpack Compose version: compiler 1.4.0, compose-bom:2023.01.00
Android Studio Build: any
Kotlin version: 1.8.0
此外,我在 Google Issue Tracker 中打开了issue
我尝试做一些研究,但我发现 NaN 值是浮点/双零除以浮点/双零的结果。
当然,我尝试将progressValue设置为NaN或零,但没有任何效果
此外,这次崩溃在某种程度上与以下问题
有关问题是你的
progressValue
变成了 NaN
(如堆栈跟踪所示)。这通常发生在我们例如除以 0。
一种解决方案是用
someData.valueX.toFloat()
调用包装您的 max(1, someData.value1.toFloat())
,这样您就永远不会除以 0。
已修复
在任何 Compose 动画进度值中,请确保该值在运行时不能为 NaN。由于某种原因,如果您将 NaN 直接传递给可组合项的 targetValue,则不会触发崩溃,但在手动检查
progressValue
中的分频器值后,崩溃随着时间的推移从 crashlytics 中消失:
val progressValue = remember(someData) {
val divisor = someData.value2.toFloat()
((someData.value1.toFloat() / divisor) * 100).takeIf { divisor != 0f } ?: 0f
}