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

如何在Jetpack Compose预览中使用依赖Application的ViewModel?

解决Jetpack Compose预览中使用AndroidViewModel的问题

预览上下文(BridgeContext)确实无法强转为Application,且预览环境没有合适的ViewModelStoreOwner来使用ViewModelProvider,可以通过以下两种方案解决:

方案1:让Composable依赖状态而非直接依赖ViewModel

这是Compose开发的最佳实践,能让UI组件更灵活,预览和测试更便捷。

步骤:

  1. 修改ProgressView,接受具体状态参数:
    将原本依赖TimeViewModel的Composable,改为接受UI所需的状态和回调:

    @Composable
    fun ProgressView(
        elapsedTime: Long,
        totalTime: Long,
        onResetClicked: () -> Unit
    ) {
        // 原UI逻辑,用传入的状态参数替代ViewModel调用
        Column {
            CircularProgressIndicator(
                progress = elapsedTime.toFloat() / totalTime.toFloat()
            )
            Button(onClick = onResetClicked) {
                Text("重置")
            }
        }
    }
    
  2. 在真实场景中从ViewModel传递状态:
    在父Composable或Activity中,从ViewModel获取状态并传给ProgressView:

    @Composable
    fun MainScreen() {
        val timeViewModel = ViewModelProvider(this)[TimeViewModel::class.java]
        val elapsedTime by timeViewModel.elapsedTime.collectAsState()
        val totalTime by timeViewModel.totalTime.collectAsState()
    
        ProgressView(
            elapsedTime = elapsedTime,
            totalTime = totalTime,
            onResetClicked = { timeViewModel.resetTimer() }
        )
    }
    
  3. 预览时直接传入模拟状态:

    @Preview(showBackground = true)
    @Composable
    fun PreviewProgress() {
        ProgressView(
            elapsedTime = 30000, // 模拟已过30秒
            totalTime = 60000, // 模拟总时长60秒
            onResetClicked = {}
        )
    }
    

方案2:为预览创建ViewModel的模拟实例

如果必须保留Composable对ViewModel的依赖,可以为预览提供一个带有模拟仓库的ViewModel实例(无需真实Room数据库)。

步骤:

  1. 调整ViewModel构造,支持依赖注入仓库:
    修改TimeViewModel,让仓库可以作为参数传入(默认使用真实仓库):

    class TimeViewModel(
        appObj: Application,
        private val timeRepository: TimeRepository = TimeRepository(appObj)
    ) : AndroidViewModel(appObj) {
        // 原ViewModel逻辑,基于timeRepository实现
        val elapsedTime = flow { emit(timeRepository.getElapsedTime()) }
        // ...
    }
    
  2. 创建模拟仓库:
    实现一个内存版的仓库,用于预览:

    class InMemoryTimeRepository : TimeRepository {
        override suspend fun getElapsedTime(): Long = 30000
        override suspend fun getTotalTime(): Long = 60000
        override suspend fun resetTimer() {}
        // 实现其他仓库方法
    }
    
  3. 预览中使用模拟ViewModel:
    创建一个空的Application实例,搭配模拟仓库构造ViewModel:

    @Preview(showBackground = true)
    @Composable
    fun PreviewProgress() {
        // 创建模拟Application
        val mockApp = object : Application() {}
        // 用模拟仓库初始化ViewModel
        val mockViewModel = TimeViewModel(mockApp, InMemoryTimeRepository())
        ProgressView(model = mockViewModel)
    }
    

注意事项

  • 预览的核心是快速查看UI效果,无需连接真实数据库或依赖完整的Android组件,优先推荐方案1,让UI与业务逻辑解耦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 11:17:10