Jetpack Compose Hilt预览报错ViewModels creation is not supported in Preview如何解决
问题解决:Jetpack Compose预览使用Hilt ViewModel报错
错误原因
你遇到的报错:
java.lang.IllegalStateException: ViewModels creation is not supported in Preview
根本原因是 Compose预览环境不支持Hilt依赖注入框架的ViewModel创建逻辑,hiltViewModel()方法依赖Hilt生成的注入组件,预览环境没有初始化这些组件,因此直接调用会抛出异常。
解决方案
方案1:拆分状态托管层与UI渲染层(最优实践)
该方案符合Compose单向数据流设计规范,彻底解决预览依赖注入问题,同时方便后续单元测试。
步骤1:改造原页面组件,拆分无状态UI实现
@ExperimentalMaterialApi @Composable fun AccountListScreen( navController: NavController, viewModel: AccountListViewModel = hiltViewModel() ) { // 从ViewModel中读取所需状态 val accountList by viewModel.accountList.collectAsStateWithLifecycle() val isLoading by viewModel.isLoading.collectAsStateWithLifecycle() // 调用无状态UI实现,传入状态和事件回调 AccountListScreenContent( accountList = accountList, isLoading = isLoading, onAccountClick = { accountId -> navController.navigate("account/detail/$accountId") }, onRefresh = viewModel::refreshAccountList ) } /** * 无状态UI实现,仅负责根据传入的状态渲染界面,所有交互通过回调抛出 */ @ExperimentalMaterialApi @Composable private fun AccountListScreenContent( accountList: List<Account>, isLoading: Boolean, onAccountClick: (String) -> Unit, onRefresh: () -> Unit ) { // 把原来AccountListScreen里的所有UI渲染逻辑移到这里 }
步骤2:预览时直接调用无状态UI,传入模拟数据
@ExperimentalMaterialApi @Preview(showBackground = true, backgroundColor = 0xFFFFFF, showSystemUi = true) @Composable fun AccountListScreenPreview() { // 直接传入模拟的测试数据即可,不需要创建ViewModel AccountListScreenContent( accountList = listOf( Account(id = "1", name = "测试账户1", balance = 100.0), Account(id = "2", name = "测试账户2", balance = 200.0) ), isLoading = false, onAccountClick = {}, onRefresh = {} ) }
方案2:手动构造ViewModel模拟实例(适配不想拆分组件的场景)
如果暂时不想拆分组件,可以手动创建ViewModel的模拟实例,直接传给页面组件,不使用hiltViewModel()获取。
@ExperimentalMaterialApi @Preview(showBackground = true, backgroundColor = 0xFFFFFF, showSystemUi = true) @Composable fun AccountListScreenPreview() { // 手动构造模拟的ViewModel,依赖的Repository等也用模拟实现 val mockRepository = MockAccountRepository() val previewViewModel = AccountListViewModel(mockRepository) AccountListScreen( navController = rememberNavController(), viewModel = previewViewModel ) }
内容的提问来源于stack exchange,提问作者Morozov
相关产品推荐
相关产品推荐

