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

升级Room、Kotlin、KSP版本后出现非空参数为空异常的解决咨询

Room升级后插入数据抛出NullPointerException问题排查与解决

问题背景

原本运行正常的Room插入数据代码,在升级以下依赖后出现NullPointerException:

  • Room版本从2.5.2升级至2.6.0
  • KSP版本从1.8.10-1.0.9升级至1.9.20-1.0.14
  • Kotlin版本从1.8.10升级至1.9.20

异常日志

12:16:29.832  W  java.lang.NullPointerException: Parameter specified as non-null is null: method androidx.sqlite.db.framework.FrameworkSQLiteProgram.bindString, parameter value
12:16:29.832  W     at androidx.sqlite.db.framework.FrameworkSQLiteProgram.bindString(Unknown Source:3)
12:16:29.832  W     at <project_package_name>.data.local.dao.ConfigurableTypeDao_Impl$1.bind(ConfigurableTypeDao_Impl.java:53)
12:16:29.832  W     at <project_package_name>.data.local.dao.ConfigurableTypeDao_Impl$1.bind(ConfigurableTypeDao_Impl.java:35)
12:16:29.832  W     at androidx.room.EntityInsertionAdapter.insert(EntityInsertionAdapter.kt:83)
12:16:29.832  W     at <project_package_name>.data.local.dao.ConfigurableTypeDao_Impl.insertAll(ConfigurableTypeDao_Impl.java:99)
12:16:29.832  W     at <project_package_name>.data.repository.SyncAllRepository.addAllConfigurableTypeToDb(SyncAllRepository.kt:175)
12:16:29.832  W     at <project_package_name>.viewModel.SyncAllViewModel$syncConfigurableTypesTable$1.invokeSuspend(SyncAllViewModel.kt:201)
12:16:29.832  W     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
12:16:29.832  W     at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
12:16:29.832  W     at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
12:16:29.832  W     at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:100)
12:16:29.832  W     at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
12:16:29.832  W     at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
12:16:29.832  W     at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
12:16:29.832  W     at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)

注:日志中SyncAllRepository.kt:175对应addAllConfigurableTypeToDb方法的return true行。

相关代码片段

Repository插入方法

fun addAllConfigurableTypeToDb(
    allConfigurableTypes: AllConfigurableType,
    database: AppDatabase
): Boolean {
    try {
        val productCategoryList = arrayListOf<ConfigurableTypeEntity>()
        for (configurableType in allConfigurableTypes.configurableTypeList) {
            productCategoryList.add(
                ConfigurableTypeEntity(
                    configurableType.id, configurableType.classType,
                    configurableType.organizationId, configurableType.name,
                    configurableType.code, configurableType.description,
                    configurableType.context, configurableType.isActive,
                    configurableType.isLocked, configurableType.isDeleted,
                    configurableType.createdBy, configurableType.createdByDate,
                    configurableType.lastModifiedBy, configurableType.lastModifiedByDate

                )
            )
        }
        database.configurableTypeDao.insertAll(*productCategoryList.toTypedArray())
        return true
    } catch (e: Exception) {
        e.printStackTrace()
        return false
    }
}

Dao接口方法

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(vararg configurableTypeEntity: ConfigurableTypeEntity)

项目级build.gradle配置

plugins {
    id 'com.android.application' version '8.1.3' apply false
    id 'com.android.library' version '8.1.3' apply false
//    id 'org.jetbrains.kotlin.android' version '1.9.0' apply false
    id 'com.google.devtools.ksp' version '1.9.20-1.0.14' apply false
    id 'org.jetbrains.kotlin.android' version '1.9.20' apply false
//    id 'com.google.devtools.ksp' version '1.8.10-1.0.9' apply false
//    id 'org.jetbrains.kotlin.android' version '1.8.10' apply false
}

已确认productCategoryList不为空,将Dao的insertAll参数从vararg改为List仍报错,回退版本则恢复正常。


原因分析

从异常栈可以看出,问题出在Room生成的ConfigurableTypeDao_Impl类的bind方法中,尝试向SQLite绑定字符串时传入了null值。核心原因是:

  1. Room 2.6.0空安全校验升级:配合Kotlin 1.9.x及新版KSP,Room生成的代码会严格遵循实体类字段的非空声明。旧版本Room可能会将null值静默转换为SQLite的NULL,但新版本直接触发NPE。
  2. 实体类字段与实际数据不匹配:ConfigurableTypeEntity中存在标记为非空的字段,但上游allConfigurableTypes返回的configurableType对象里,对应字符串字段为null,导致绑定SQLite参数时传入null,触发异常。

解决步骤

1. 检查并修正实体类字段声明

找到ConfigurableTypeEntity类,针对每个字符串/布尔类型字段做处理:

  • 如果业务允许字段为null:将字段改为可空类型(添加?,比如val name: String?),若之前加了@ColumnInfo(nullable = false)则移除该注解。
  • 如果字段必须非空:检查上游数据来源,确保对应字段不会返回null,或者在插入前添加非空校验。

2. 修复Repository的数据转换逻辑

在创建ConfigurableTypeEntity实例时,为可能为null的字段添加默认值兜底,示例:

ConfigurableTypeEntity(
    configurableType.id, 
    configurableType.classType ?: "",
    configurableType.organizationId ?: "",
    configurableType.name ?: "",
    configurableType.code ?: "",
    configurableType.description ?: "",
    configurableType.context ?: "",
    configurableType.isActive ?: false,
    configurableType.isLocked ?: false,
    configurableType.isDeleted ?: false,
    configurableType.createdBy ?: "",
    configurableType.createdByDate ?: 0,
    configurableType.lastModifiedBy ?: "",
    configurableType.lastModifiedByDate ?: 0
)

3. 可选:升级Room到最新稳定版

如果是Room 2.6.0的已知代码生成bug,尝试升级到2.6.1及以上版本,新版本可能修复了空安全相关的问题。

4. 清理并重新构建项目

修改实体类或依赖后,执行Clean Project和Rebuild Project,确保KSP重新生成正确的Dao实现类。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 08:30:05