从Room数据库获取MAX值时触发NullPointerException的解决方法
问题:从Room数据库获取指定列MAX值并返回Long类型时,添加第一个条目触发NullPointerException如何修复?
异常信息
java.lang.NullPointerException: Attempt to invoke virtual method 'long java.lang.Number.longValue()' on a null object reference
相关代码
ShoppingListEntity
@Entity(tableName = "shopping_lists") data class ShoppingListEntity( @PrimaryKey(autoGenerate = true) var id: Long = 0L, @ColumnInfo(name = "name") val name: String, @ColumnInfo(name = "number_of_items") val numberOfItems: Long, @ColumnInfo(name = "list_total") val listTotal: String, @ColumnInfo(name = "sort_order") val sortOrder: String )
ShoppingListItemEntity
@Entity( tableName = "shopping_list_items", foreignKeys = [ForeignKey( entity = ShoppingListEntity::class, parentColumns = arrayOf("id"), childColumns = arrayOf("shopping_list_id"), onUpdate = ForeignKey.CASCADE, onDelete = ForeignKey.CASCADE )] ) data class ShoppingListItemEntity( @PrimaryKey(autoGenerate = true) var id: Long = 0L, @ColumnInfo(name = "shopping_list_id") var shoppingListId: Long = 0L, ... @ColumnInfo(name = "custom_sort_index") val customSortIndex: Long )
Dao
@Query("SELECT MAX(custom_sort_index) FROM shopping_list_items WHERE shopping_list_id = :listId") suspend fun getMaxCustomSortIndex(listId: Long): Long
Repository
override suspend fun getMaxCustomSortIndex(listId: Long): Long { return withContext(Dispatchers.IO) { shoppingListItemDao.getMaxCustomSortIndex(listId) } }
Use Case
class GetMaxCustomSortIndexInItemsTableUseCase@Inject constructor( private val shoppingListItemsRepository: ShoppingListItemsRepository ) { suspend operator fun invoke(listId: Long): Long { return shoppingListItemsRepository.getMaxCustomSortIndex(listId) } }
ViewModel
suspend fun addShoppingListItemToDb() { if (!_shoppingListScreenState.value.isNameError && !_shoppingListScreenState.value.isCategoryError) { viewModelScope.launch { val listId = _shoppingListState.value!!.id // 此处抛出NullPointerException val maxCustomSortIndex = getMaxCustomSortIndexInItemsTableUseCase(listId) val item = _shoppingListItemState.value addShoppingListItemUseCase(item.copy(customSortIndex = maxCustomSortIndex + 1)) _listItemsLoadingState.value = ListItemsState.Success(_shoppingListItemsState.value) setStateValue(IS_SCROLL_TO_LAST_ITEM_IN_LAZYCOLUMN_STR, true) } } }
解决方案
问题核心是:当指定listId下无任何条目时,MAX(custom_sort_index)返回NULL,但Room尝试将NULL转换为非空Long类型时,会触发自动拆箱操作,从而抛出空指针异常。
提供两种修复方案:
方案一:SQL层直接处理空值
使用COALESCE函数,当MAX结果为NULL时返回默认值(比如0),这样Room可以直接将结果转为非空Long:
@Query("SELECT COALESCE(MAX(custom_sort_index), 0) FROM shopping_list_items WHERE shopping_list_id = :listId") suspend fun getMaxCustomSortIndex(listId: Long): Long
此方案无需修改其他层代码,逻辑简洁高效。
方案二:Dao层返回可空类型,Repository处理空值
- 修改Dao返回类型为
Long?,允许返回空值:
@Query("SELECT MAX(custom_sort_index) FROM shopping_list_items WHERE shopping_list_id = :listId") suspend fun getMaxCustomSortIndex(listId: Long): Long?
- 在Repository中对空值做兜底处理,返回默认值:
override suspend fun getMaxCustomSortIndex(listId: Long): Long { return withContext(Dispatchers.IO) { shoppingListItemDao.getMaxCustomSortIndex(listId) ?: 0L } }
此方案将空值处理逻辑放在业务层,适合需要灵活调整默认值的场景。
内容的提问来源于stack exchange,提问作者Raj Narayanan
相关产品推荐
相关产品推荐

