Jetpack Compose预览调用hiltViewModel<>()出现崩溃问题如何解决
问题根因
Compose 预览运行时不会初始化项目的 Hilt 依赖注入环境,hiltViewModel() 无法通过 Hilt 获取带构造参数的 ViewModel 实例,只能降级尝试调用 ViewModel 的无参构造方法,你的 HomeViewModel 没有无参构造,所以抛出找不到构造方法的异常。线上运行时 Hilt 已经完成初始化,所以不会有问题,和 Compose 版本无关。
可行解决方案
方案1:拆分有状态/无状态 Composable(最推荐)
把原来的组件拆成两层,符合 Compose 最佳实践,同时方便后续单元测试:
- 外层有状态组件:负责获取 ViewModel、处理业务逻辑、给内层组件传参数,业务逻辑层直接调用该组件
- 内层无状态组件:只负责根据传入的参数渲染UI,预览直接针对内层组件编写,传入模拟数据即可
// 外层有状态组件 fun EngagementBotChart(modifier: Modifier = Modifier) { val newHomeViewModel = hiltViewModel<HomeViewModel>() EngagementBotChartStateless( modifier = modifier, // 把需要的数据从ViewModel取出来传给内层 chartData = newHomeViewModel.chartData.value ) } // 内层无状态组件,仅做渲染 @Composable fun EngagementBotChartStateless( modifier: Modifier = Modifier, chartData: ChartData // 替换为你实际需要的参数类型 ) { AndroidView( modifier = modifier.fillMaxSize(), factory = { context -> }, update = { view -> } ) } // 预览直接针对无状态组件编写,传入模拟数据 @Preview @Composable fun EngagementBotChartPreview() { YourAppTheme { EngagementBotChartStateless( chartData = ChartData.mock() // 自行构造模拟数据 ) } }
方案2:预览环境返回模拟 ViewModel
如果不想拆分组件,可以通过 LocalInspectionMode 判断当前是否是预览环境,预览时直接构造模拟的 ViewModel 实例,不走 Hilt 获取,改动量最小:
@Composable fun EngagementBotChart(modifier: Modifier = Modifier) { val newHomeViewModel = if (LocalInspectionMode.current) { // 预览环境直接构造模拟ViewModel,自行实现模拟逻辑 HomeViewModel(mockRepository()) } else { hiltViewModel<HomeViewModel>() } AndroidView( modifier = modifier.fillMaxSize(), factory = { context -> }, update = { view -> } ) }
方案3:使用Hilt预览支持(适合复杂场景)
如果你的预览需要依赖多个Hilt注入的实例,可以引入Hilt的预览支持库,配置预览专用的Hilt组件,不过配置成本更高,适合大型项目使用:
- 给预览的Activity添加
@AndroidEntryPoint注解 - 预览时使用
@HiltPreview注解(需要配套的Hilt版本支持)
内容的提问来源于stack exchange,提问作者Mobin Yardim
相关产品推荐
相关产品推荐

