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

Kotlin调用ViewModel方法提示lateinit属性_mails未初始化该如何解决

报错根因

  • viewModelScope.launch(Dispatchers.IO) 启动的是异步任务,不会阻塞ViewModel初始化的主线程。数据库查询属于耗时操作,执行时序会晚于Fragment的onStart生命周期回调
  • 你在onStart中同步调用getAllConnections()时,IO线程的_mails赋值操作还未完成,lateinit修饰的变量还未初始化,就抛出了对应异常

解决方案(推荐使用响应式架构实现)

Android MVVM架构下推荐使用StateFlow实现数据的响应式通知,无需手动控制异步任务时序,数据加载完成后自动更新UI:

1. 修改ConnectionViewModel代码

class ConnectionViewModel(
    val database: ConnectionDataBaseDao,
    application: Application) :  AndroidViewModel(application){

    // 私有可变状态流,初始值设置为空列表
    private val _mails = MutableStateFlow<List<Connection>>(emptyList())
    // 对外暴露不可变状态流,避免外部随意修改数据
    val mails = _mails.asStateFlow()

    init {
        viewModelScope.launch(Dispatchers.IO) {
            // 数据库查询完成后更新状态流的值
            _mails.value = database.getAllConnections()
        }
    }
}

2. 修改ConnectionFragment代码

移除onStart中的同步调用逻辑,改为监听StateFlow的数值变化,数据返回后再设置适配器:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    // 绑定生命周期监听数据变化
    lifecycleScope.launch {
        repeatOnLifecycle(Lifecycle.State.STARTED) {
            viewModel.mails.collect { mailList ->
                val mails = mailList.map { it.mailId }
                val adapter = ArrayAdapter<String>(requireContext(), android.R.layout.simple_list_item_1, mails)
                binding.mail.setAdapter(adapter)
            }
        }
    }
}

补充说明

如果你不想使用响应式方案,也可以将_mails的lateinit修饰符移除,直接初始化赋值为emptyList(),但这种方式你仍然需要额外处理数据加载完成后刷新UI的逻辑,否则永远只会显示空列表,因此不推荐使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 11:12:02