Room数据库存储OffsetDateTime字段报游标读取错误的解决方法
报错原因
Room默认仅支持映射SQLite原生支持的存储类型(基础数值类型、字符串、字节数组等),java.time.OffsetDateTime属于Java 8引入的时间API类型,不在Room默认类型映射范围内,因此无法直接从Cursor读取字段值,触发报错。
修复方案
通过Room提供的TypeConverter机制自定义类型转换逻辑,将OffsetDateTime转换为Room可持久化存储的类型(推荐使用ISO标准格式字符串存储,可完整保留时区偏移信息,不建议存Long型时间戳),具体操作步骤如下:
- 编写类型转换类
新建转换器类,通过@TypeConverter注解实现两个方向的转换逻辑:数据库存储的字符串转OffsetDateTime、OffsetDateTime转存入数据库的字符串。
Java实现代码:
Kotlin实现代码:import androidx.room.TypeConverter; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; public class OffsetDateTimeConverters { private static final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter.ISO_OFFSET_DATE_TIME; @TypeConverter public static OffsetDateTime stringToOffsetDateTime(String storedValue) { return storedValue == null ? null : OffsetDateTime.parse(storedValue, ISO_FORMATTER); } @TypeConverter public static String offsetDateTimeToString(OffsetDateTime dateTime) { return dateTime == null ? null : dateTime.format(ISO_FORMATTER); } }import androidx.room.TypeConverter import java.time.OffsetDateTime import java.time.format.DateTimeFormatter class OffsetDateTimeConverters { private val isoFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME @TypeConverter fun stringToOffsetDateTime(storedValue: String?): OffsetDateTime? { return storedValue?.let { OffsetDateTime.parse(it, isoFormatter) } } @TypeConverter fun offsetDateTimeToString(dateTime: OffsetDateTime?): String? { return dateTime?.format(isoFormatter) } } - 注册转换器到Room数据库
在自定义的RoomDatabase实现类上添加@TypeConverters注解,传入刚才编写的转换器类,即可让全局所有实体、DAO识别该转换规则:
Java示例:
Kotlin示例:import androidx.room.Database; import androidx.room.RoomDatabase; import androidx.room.TypeConverters; @Database(entities = {YourDataClass.class}, version = 1) @TypeConverters({OffsetDateTimeConverters.class}) public abstract class AppDatabase extends RoomDatabase { public abstract YourDataDao yourDataDao(); }import androidx.room.Database import androidx.room.RoomDatabase import androidx.room.TypeConverters @Database(entities = [YourDataClass::class], version = 1) @TypeConverters(OffsetDateTimeConverters::class) abstract class AppDatabase : RoomDatabase() { abstract fun yourDataDao(): YourDataDao } - 低版本兼容配置(minSdk < 26时必须配置)
如果项目最低支持版本低于API 26,需要开启核心库脱糖支持,否则低版本设备无法使用java.time包下的类:- 在模块级
build.gradle中开启脱糖配置:
android { compileOptions { coreLibraryDesugaringEnabled true sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } // Kotlin项目需额外配置kotlin编译选项的jvmTarget为1.8 }- 添加脱糖依赖:
dependencies { coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' } - 在模块级
注意事项
- 不要将
OffsetDateTime转换为Long型时间戳存储,会丢失原始时区偏移信息,除非业务场景明确不需要保留原始时区。 - 转换器方法需声明为公开可访问,不要写成私有方法,Java中需加
static修饰。 - 配置完成后如果仍有报错,可执行Clean Project后重新编译,让Room注解处理器重新生成映射代码。
内容的提问来源于stack exchange,提问作者T D Nguyen
相关产品推荐
相关产品推荐

