升级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值。核心原因是:
- Room 2.6.0空安全校验升级:配合Kotlin 1.9.x及新版KSP,Room生成的代码会严格遵循实体类字段的非空声明。旧版本Room可能会将null值静默转换为SQLite的NULL,但新版本直接触发NPE。
- 实体类字段与实际数据不匹配:
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
相关产品推荐
相关产品推荐

