升级后assistedViewModel触发ArrayIndexOutOfBoundsException异常
问题
完成以下版本升级后(此前运行正常),使用assistedViewModel创建TimeslotViewModel时触发ArrayIndexOutOfBoundsException异常:
- kotlinCompilerExtensionVersion = "1.4.3"
- jvmTarget设为"17",sourceCompatibility与targetCompatibility设为Java 17
- kotlin-android插件版本为1.8.10
- com.android.application插件版本为8.1.0-alpha11
报错位置代码
assistedViewModel { TimeslotViewModel.provideFactory(timeslotViewModelFactory(), it.toInt()) }
相关代码
导航代码
@Keep @Composable @InternalCoroutinesApi @ExperimentalCoroutinesApi fun SetupNavigationHost( navController: NavHostController, ) { NavHost( navController = navController, startDestination = Screen.MainScreen.route, ) { composable( Screen.MainScreen.route, deepLinks = listOf(navDeepLink { uriPattern = Screen.MainScreen.deepLinkRoute }) ) { HomeScreen( navController = navController ) } composable( Screen.ShowTimeslotDetails.route, arguments = listOf( navArgument("id") {} ) ) { backStackEntry -> backStackEntry.arguments?.getString("id") ?.let { val viewModel: TimeslotViewModel = assistedViewModel { TimeslotViewModel.provideFactory(timeslotViewModelFactory(), it.toInt()) } ShowTimeslotDetails( timeslotId = it.toInt(), viewModel = viewModel, navController = navController ) } } } }
ViewModel代码
@Module @InstallIn(ActivityRetainedComponent::class) interface AssistedInjectModule class TimeslotViewModel @AssistedInject constructor( @Assisted private val timeslotId: Int, ) : ViewModel() { @AssistedFactory interface Factory { fun create(timeslotId: Int): TimeslotViewModel } @Suppress("UNCHECKED_CAST") companion object { fun provideFactory(factory: Factory, id: Int): ViewModelProvider.Factory { return object : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>): T { return factory.create(id) as T } } } } }
MainActivity代码
@AndroidEntryPoint class MainActivity : ComponentActivity() { @EntryPoint @InstallIn(ActivityComponent::class) interface ViewModelFactoryProvider { fun timeslotViewModelFactory(): TimeslotViewModel.Factory } ... }
报错堆栈信息
FATAL EXCEPTION: main Process: com.example.versions10, PID: 20465 java.lang.ArrayIndexOutOfBoundsException: length=109; index=-1 at java.util.ArrayList.remove(ArrayList.java:506) at androidx.compose.runtime.Stack.pop(Stack.kt:26) at androidx.compose.runtime.ComposerImpl.exitGroup(Composer.kt:2246) at androidx.compose.runtime.ComposerImpl.end(Composer.kt:2408) at androidx.compose.runtime.ComposerImpl.endGroup(Composer.kt:1578) at androidx.compose.runtime.ComposerImpl.endRoot(Composer.kt:1462) at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3367) at androidx.compose.runtime.ComposerImpl.recompose$runtime_release(Composer.kt:3307) at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:772) at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:1047) at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:124) at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:541) at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:510) at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:34) at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.android.kt:109) at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch(AndroidUiDispatcher.android.kt:41) at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:69) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1299) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1309) at android.view.Choreographer.doCallbacks(Choreographer.java:923) at android.view.Choreographer.doFrame(Choreographer.java:847) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1283) at android.os.Handler.handleCallback(Handler.java:942) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:226) at android.os.Looper.loop(Looper.java:313) at android.app.ActivityThread.main(ActivityThread.java:8741) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067) Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [androidx.compose.runtime.PausableMonotonicFrameClock@cb194e5, androidx.compose.ui.platform.MotionDurationScaleImpl@1185bba, StandaloneCoroutine{Cancelling}@f2dea6b, AndroidUiDispatcher@dbb99c8]
解决方案
1. 降级AGP到稳定版
当前使用的com.android.application是8.1.0-alpha11预览版,这类版本存在兼容性风险,建议降级到最新稳定版(如8.0.2),同时确保kotlin-android插件版本与AGP版本匹配。
2. 调整Composable内ViewModel创建逻辑
原代码在nullable链式调用的let块内创建ViewModel,可能导致Compose重组时出现栈异常。重构代码结构,显式处理id为空的情况:
composable( Screen.ShowTimeslotDetails.route, arguments = listOf( navArgument("id") {} ) ) { backStackEntry -> val id = backStackEntry.arguments?.getString("id")?.toIntOrNull() if (id != null) { val viewModel: TimeslotViewModel = assistedViewModel { TimeslotViewModel.provideFactory(timeslotViewModelFactory(), id) } ShowTimeslotDetails( timeslotId = id, viewModel = viewModel, navController = navController ) } else { // 处理id无效场景,例如返回上一页 LaunchedEffect(Unit) { navController.popBackStack() } } }
3. 同步依赖版本
确保Hilt、Compose相关依赖版本与kotlin、AGP版本兼容:
- 升级Hilt到最新稳定版(如
2.48) - 确保Compose runtime、ui等依赖版本与kotlinCompilerExtensionVersion匹配(1.4.x对应Compose BOM 2023.03.00)
内容的提问来源于stack exchange,提问作者Sepidehye Fanavari
相关产品推荐
相关产品推荐

