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

Kotlin协程异常:androidx.lifecycle.MutableLiveData对象触发NullPointerException

分析与解决你的Kotlin Coroutines + Room空指针问题

咱们先直接看错误日志的核心信息:

java.lang.NullPointerException: 尝试对空对象引用调用虚拟方法 'void androidx.lifecycle.MutableLiveData.setValue(java.lang.Object)'
at com.google.samples.apps.trackmysleepquality.sleeptracker.SleepTrackerViewModel$initializeTonight$1.invokeSuspend(SleepTrackerViewModel.kt:56)

你可能会疑惑:明明tonight已经声明为MutableLiveData<SleepNight?>(),怎么还会触发空指针?其实这是个很容易踩的类初始化顺序坑!

问题根源:初始化顺序搞反了

看你ViewModel里的代码结构:

init {
    initializeTonight()
}

private var tonight = MutableLiveData<SleepNight?>()

在Kotlin中,类的初始化是严格按照代码书写顺序执行的:

  1. 先执行主构造函数
  2. 再按从上到下的顺序执行init块和属性初始化代码

你的init块写在了tonight属性声明的前面,导致init调用initializeTonight()时,tonight还没被初始化(此时它的值是null)。等到协程里执行tonight.value = getTonightFromDatabase()时,本质是对null对象调用setValue方法,直接触发空指针!

解决方案:调整属性声明顺序

只需要把tonight的属性声明移到init块前面就行,让它在init执行前完成初始化:

class SleepTrackerViewModel(
    val database: SleepDatabaseDao,
    application: Application
) : AndroidViewModel(application) {

    /**
     * [tonight] is the object that holds the most recent [SleepNight]
     */
    private var tonight = MutableLiveData<SleepNight?>()

    init {
        initializeTonight()
    }

    // 剩余代码保持不变...
}

这样当init块调用initializeTonight()时,tonight已经是一个合法的MutableLiveData实例,协程里给它赋值就不会有空指针问题了。

额外可读性优化建议

顺便看了下getTonightFromDatabase()的逻辑,虽然功能没问题,但可以优化下可读性:

// 原代码
if (night?.endTimeMilli != night?.startTimeMilli) {
    night = null
}

// 优化后
if (night != null && night.endTimeMilli != night.startTimeMilli) {
    night = null
}

这样可以避免空安全链式调用带来的歧义,逻辑更直观。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 21:22:50