You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何Mock ViewModel以使用Jetpack Compose Preview?解决Hilt注入ViewModel预览报错问题

解决Compose Preview中无法使用Hilt注入ViewModel的问题

这个问题我之前也碰到过,确实挺头疼的——Compose Preview的沙盒环境不支持Hilt的依赖注入容器初始化,所以直接调用hiltViewModel()肯定会报错。下面给你两种最常用的解决思路,亲测有效:

方法一:给MainScreen添加可传入的ViewModel参数(推荐)

核心思路是让MainScreen不强制依赖Hilt的自动注入,而是允许外部传入ViewModel实例,这样正常运行时用默认的hiltViewModel(),预览时手动传一个mock/测试用的ViewModel。

  1. 保持原MainScreen的兼容性:
    你的原代码不用大改,只是保留默认参数的同时,允许外部传入ViewModel:

    @Composable
    fun MainScreen(
        viewModel: MainScreenViewModel = hiltViewModel()
    ) {
        // 你的Compose UI逻辑,比如使用viewModel的状态
        Text(text = viewModel.uiState.value.title)
    }
    
  2. 创建Mock/测试用的ViewModel:
    根据你的MainScreenViewModel的逻辑,写一个专门用于预览的子类或者直接实例化(如果依赖可以mock的话)。比如你的ViewModel有依赖,用Mockito快速mock:

    // 假设你的ViewModel是这样的
    class MainScreenViewModel @Inject constructor(
        private val albumRepository: AlbumRepository
    ) : ViewModel() {
        val uiState = MutableStateFlow(AlbumUiState(albums = emptyList()))
        // 其他业务逻辑
    }
    
    // 预览用的Mock ViewModel
    class MockMainScreenViewModel : MainScreenViewModel(mock()) {
        // 给预览提供测试数据
        init {
            uiState.value = AlbumUiState(
                albums = listOf(
                    Album(id = 1, name = "测试专辑1"),
                    Album(id = 2, name = "测试专辑2")
                )
            )
        }
    }
    

    如果你的ViewModel没有复杂依赖,甚至可以直接在预览里new一个(前提是构造函数允许)。

  3. 修改Preview函数传入Mock ViewModel:
    现在预览里就可以手动传入mock的实例了:

    @Preview(showBackground = true)
    @Composable
    fun DefaultPreview() {
        AlbumExpoTheme {
            MainScreen(
                viewModel = MockMainScreenViewModel()
            )
        }
    }
    

方法二:使用ViewModelFactory(适合更复杂的场景)

如果你的ViewModel需要特定的依赖,又不想写mock子类,可以自定义一个ViewModelFactory,在预览里用它创建实例:

class PreviewMainScreenViewModelFactory : ViewModelProvider.Factory {
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        val mockRepo = mock(AlbumRepository::class.java)
        // 可以提前给mockRepo设置返回值
        `when`(mockRepo.getAlbums()).thenReturn(flowOf(listOf(Album(id=1, name="测试专辑"))))
        return MainScreenViewModel(mockRepo) as T
    }
}

// 预览里使用Factory创建ViewModel
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    AlbumExpoTheme {
        val viewModel = viewModel(factory = PreviewMainScreenViewModelFactory())
        MainScreen(viewModel = viewModel)
    }
}

关键注意点

  • 预览的核心是展示UI,所以Mock ViewModel只需要提供UI所需的测试状态数据即可,不用实现完整的业务逻辑。
  • 不要在预览里依赖真实的数据源或复杂的依赖注入逻辑,保持预览的独立性和快速加载性。

内容的提问来源于stack exchange,提问作者barryalan2633

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.01 01:07:29