保存到 Room 时数据类型为 false

Data type false when saving to Room

我正在用 Kotlin 编写 android 应用程序。尝试使用 room 将数据保存到本地存储。 但是我有一个错误:“无法弄清楚如何将这个字段保存到数据库中。你可以考虑为它添加一个类型转换器”。

我尝试根据文档并借助 Stack Overflow 上的示例将转换器转换为字符串。但我仍然有同样的错误。请告诉我如何避免它。 这是我的 class 我形成结构的地方:

    data class Request(
    val method: String?,
    val url: String?,
    val headers: Map<String, List<String>>?,
    val body: String,
    val size: Int,
)

data class Response(
    val code: Int?,
    val headers: Map<String, List<String>>?,
    val body: String?,
    val size: Int?,
)

@Entity
data class Packet(
    @PrimaryKey val id: Int,
    val userId: String,
    val deviceId: String,
    val sessionId: String,
    val timestamp: Long?,
    val duration: Int?,
    val protocol: String?,
    @Embedded val request: Request?,
    @Embedded val response: Response?,
)

这就是我保存数据的方式

    @Database(
    version = 1,
    entities = [Packet::class]
)

abstract class NetworkDatabase : RoomDatabase() {
    abstract fun packetDao(): PacketDao
}

SQLite(room 是包装器的关系数据库)仅限于 table(@Entity 注释 class)具有可以包含单个值的列仅限于一小组类型(TEXT(String) INTEGER(Int,Long,....) REAL(Float,Double,....) BLOB(ByteArray) 和 NUMERIC(Room 不可用))

As Such youMap<String, List<String>>无法直接存储。您需要将其转换为单个值或更正确,在列表的情况下,在数据库术语中另一个 table。但是,通常会放弃使用 table 以更方便地转换为单个值,通常是将 object(s) 表示为字符串的 JSON 字符串。

Room 通过使用两个注释 @TypeConverter@TypeConverters

来促进 TypeConverter 的使用
  • 前者先于执行从 object 到受支持值的转换的函数,并且始终是执行相反操作的补充函数。
  • 第二个定义包含函数及其作用域的 classes。

所以你需要有带@TypeConvert 注释的函数和一个带 suitable 范围的@TypeConverters(在@Database 级别给出了最广泛的范围)。

当您在数据包中嵌入请求和响应时 classes (table)。您还会遇到列命名问题,因为 headers、body 和大小 variables/fields 具有相同的名称。

此外,如果使用 JSON 字符串进行最方便的转换,List、Maps 和 Arrays 处理起来会有点困难。控股class可以简化事情。

1).由于 JSON 将用于从 object 转换为 JSON 字符串,因此您应该为 com.google.code.gson 添加依赖项,例如implementation 'com.google.code.gson:gson:2.9.0' 到您的构建 gradle(模块)。

  • 还有其他选择

2).修改 classes 以便 variable/field 名称不会与列名称重复,并另外为地图引入一个控股 class (一个适合 Response 和 Request classes) .所以 classes 可能是 :-

/* Holding Class */
data class Mapping (
    val header: Map<String, List<String>>
)

/* Note changed column names */
data class Request(
    val requestMethod: String?,
    val requestUrl: String?,
    val requestHeaders: Mapping?,
    val requestBody: String,
    val requestSize: Int
)

/* Note changed column names */
data class Response(
    val responseCode: Int?,
    val responseHeaders: Mapping?,
    val responseBody: String?,
    val responseSize: Int?
)

@Entity
data class Packet(
    @PrimaryKey val id: Int,
    val userId: String,
    val deviceId: String,
    val sessionId: String,
    val timestamp: Long?,
    val duration: Int?,
    val protocol: String?,
    @Embedded val request: Request?,
    @Embedded val response: Response?
)

3).为 TypeConverter 函数添加一个 class,将持有(映射)class to/from 转换为 object 的 JSON 字符串表示,例如:-

class RoomTypeConverters {

    @TypeConverter
    fun fromMappingToJSONString(mapping: Mapping): String {
        return Gson().toJson(mapping)
    }
    @TypeConverter
    fun fromJSONStringToMapping(jsonString: String): Mapping {
        return Gson().fromJson(jsonString,Mapping::class.java)
    }
}

4).添加具有 suitable 范围的 @TypeConverters 注释,完整范围在 @Database 级别,因此注释为 class 的 @Database 可以是 :-

@TypeConverters(value = [RoomTypeConverters::class]) //<<<<<<<<<< defines the classes that include the @TypeConverter annotated functions
@Database(entities = [Packet::class], version = 1, exportSchema = false)
abstract class TheDatabase: RoomDatabase() {
    ....
}

使用上面的方法构建成功,例如

Executing tasks: [:app:assembleDebug] in project E:\AndroidStudioApps\SO72128161KotlinRoomTypeConverters

> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuild UP-TO-DATE
> Task :app:mergeDebugNativeDebugMetadata NO-SOURCE
> Task :app:compileDebugAidl NO-SOURCE
> Task :app:compileDebugRenderscript NO-SOURCE
> Task :app:generateDebugBuildConfig UP-TO-DATE
> Task :app:checkDebugAarMetadata UP-TO-DATE
> Task :app:generateDebugResValues UP-TO-DATE
> Task :app:generateDebugResources UP-TO-DATE
> Task :app:mergeDebugResources UP-TO-DATE
> Task :app:packageDebugResources UP-TO-DATE
> Task :app:parseDebugLocalResources UP-TO-DATE
> Task :app:createDebugCompatibleScreenManifests UP-TO-DATE
> Task :app:extractDeepLinksDebug UP-TO-DATE
> Task :app:processDebugMainManifest UP-TO-DATE
> Task :app:processDebugManifest UP-TO-DATE
> Task :app:processDebugManifestForPackage UP-TO-DATE
> Task :app:processDebugResources UP-TO-DATE
> Task :app:javaPreCompileDebug UP-TO-DATE
> Task :app:mergeDebugShaders UP-TO-DATE
> Task :app:compileDebugShaders NO-SOURCE
> Task :app:generateDebugAssets UP-TO-DATE
> Task :app:mergeDebugAssets UP-TO-DATE
> Task :app:compressDebugAssets UP-TO-DATE
> Task :app:processDebugJavaRes NO-SOURCE
> Task :app:checkDebugDuplicateClasses UP-TO-DATE
> Task :app:desugarDebugFileDependencies UP-TO-DATE
> Task :app:mergeExtDexDebug UP-TO-DATE
> Task :app:mergeLibDexDebug UP-TO-DATE
> Task :app:mergeDebugJniLibFolders UP-TO-DATE
> Task :app:mergeDebugNativeLibs NO-SOURCE
> Task :app:stripDebugDebugSymbols NO-SOURCE
> Task :app:validateSigningDebug UP-TO-DATE
> Task :app:writeDebugAppMetadata UP-TO-DATE
> Task :app:writeDebugSigningConfigVersions UP-TO-DATE
> Task :app:kaptGenerateStubsDebugKotlin
> Task :app:kaptDebugKotlin
> Task :app:compileDebugKotlin
> Task :app:compileDebugJavaWithJavac
> Task :app:mergeDebugJavaResource UP-TO-DATE
> Task :app:dexBuilderDebug
> Task :app:mergeProjectDexDebug
> Task :app:packageDebug
> Task :app:createDebugApkListingFileRedirect UP-TO-DATE
> Task :app:assembleDebug

BUILD SUCCESSFUL in 3s
33 actionable tasks: 7 executed, 26 up-to-date

Build Analyzer results available

此外,您还可以看到 table 数据包 table 将使用 SQL(由 Room 在生成的 java 代码中生成)按照:-

_db.execSQL("CREATE TABLE IF NOT EXISTS `Packet` (`id` INTEGER NOT NULL, `userId` TEXT NOT NULL, `deviceId` TEXT NOT NULL, `sessionId` TEXT NOT NULL, `timestamp` INTEGER, `duration` INTEGER, `protocol` TEXT, `requestMethod` TEXT, `requestUrl` TEXT, `requestHeaders` TEXT, `requestBody` TEXT, `requestSize` INTEGER, `responseCode` INTEGER, `responseHeaders` TEXT, `responseBody` TEXT, `responseSize` INTEGER, PRIMARY KEY(`id`))");