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

如何使用ViewModel从Repository获取API数据及现有代码正确性排查

代码问题修正

1. AppModule 问题修复

现有代码中providesPokemonRepository方法命名和返回的MovieRepository类型不匹配,属于命名规范问题,修正后代码如下:

@Module
@InstallIn(SingletonComponent::class)
object AppModule {

    @Provides
    @Singleton
    // 修正方法命名,和返回的MovieRepository保持一致
    fun providesMovieRepository(
        api: MovieApiService
    ) = MovieRepository(api)

    @Singleton
    @Provides
    fun providesMovieApi(): MovieApiService {
        return Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(MovieApiService::class.java)
    }
}

Repository代码本身没有逻辑问题,可以正常使用。

2. ViewModel 问题修复

现有代码存在两个核心问题:

  • errorMessage用val声明,配合by mutableStateOf时无法修改值,需要改为var
  • getMovies方法拿到请求结果后没有做状态分发,也没有处理加载、成功、失败的状态流转
    修正后代码如下:
@HiltViewModel
class MovieViewModel @Inject constructor(private val repository: MovieRepository) : ViewModel() {

    // 用by mutableStateOf的变量需要声明为var才能修改值
    var response: List<MoviesItem> by mutableStateOf(listOf())
    var errorMessage: String by mutableStateOf("")
    var isLoading by mutableStateOf(false)

    fun getMovies() = viewModelScope.launch {
        isLoading = true
        when(val result = repository.getMovieLists()) {
            is Resource.Success -> {
                response = result.data
                errorMessage = ""
            }
            is Resource.Error -> {
                errorMessage = result.message ?: "未知错误"
                response = emptyList()
            }
        }
        isLoading = false
    }
}

请确保你的Resource密封类定义符合通用规范,参考示例:

sealed class Resource<out T> {
    data class Success<out T>(val data: T) : Resource<T>()
    data class Error(val message: String?) : Resource<Nothing>()
}
调用示例

以Compose页面为例,调用方式如下:

@Composable
fun MovieScreen(viewModel: MovieViewModel = hiltViewModel()) {
    LaunchedEffect(Unit) {
        viewModel.getMovies()
    }
    when {
        viewModel.isLoading -> {
            // 渲染加载中UI
        }
        viewModel.errorMessage.isNotEmpty() -> {
            // 渲染错误提示UI
        }
        else -> {
            // 用viewModel.response渲染电影列表
        }
    }
}
学习建议
  • 你遇到的问题属于Jetpack组件组合使用的熟练度问题,不是基础编码能力不足,不需要自我怀疑。这类分层架构的写法有固定套路,完成2-3个完整的小demo即可熟练掌握。
  • 可以拆分模块逐个突破:先单独搞懂Hilt依赖注入的规则,再练熟Repository+协程的网络请求封装,最后搞清楚ViewModel和UI状态的绑定逻辑,不要一开始就把所有组件堆在一起写,容易混乱。
  • 写完功能后可以对照官方文档核对每个组件的写法规范,比如依赖注入的命名、State的正确声明方式、viewModelScope的生命周期这些细节,多注意几次就能避免低级错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 23:27:04