【问题标题】:Kotlin typealias with Android Room TypeConverters带有 Android Room TypeConverters 的 Kotlin 类型别名
【发布时间】:2018-04-25 05:51:42
【问题描述】:

我已经使用 Kotlin 的 typealias 定义了一个 E164 电话号码类型:

typealias E164 = String

这让我在代码中传递电话号码时的意图更加清晰,而不仅仅是传递字符串。我承认没有实际强制使用正确的类型,但这对我来说效果很好。

现在我想将 E164 存储在 Android Room 数据库中。这在没有 typealias 的情况下工作,但使用 typealias 它需要一个 TypeConverters。我试过这个:

@Entity data class MyModel(@PrimaryKey val e164: E164, val someOtherThing: String)

class E164Converters {
    @TypeConverter
    fun toE164(value: String): E164 = value

    @TypeConverter
    fun toString(e164: E164): String = e164
}

编译器不喜欢 E164Converters 类的自动生成的 Java,因为 toString 和 toE164 方法都定义了相同的 String -> String 转换。

error: Multiple methods define the same conversion. Conflicts with these: CustomTypeConverter(type=E164Converters, method=toString(java.lang.String), from=java.lang.String, to=java.lang.String) public final java.lang.String toE164(@org.jetbrains.annotations.NotNull()

但是如果我不定义 TypeConverters,那么编译器不知道如何将 E164 放入数据库:

error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
private final error.NonExistentClass e164 = null;

有人知道如何实现吗?

【问题讨论】:

    标签: kotlin android-room


    【解决方案1】:

    您不需要E164Converters。您可以将E164 用作String。喜欢

    val a: E164 = "blabla"
    
    fun f(x: String) = x
    f(a) // compiles
    

    我猜你在写类似的东西

    fun processPhoneNumber(a: E164) {
      // blabla
    }
    

    你可以像processPhoneNumber("110")一样调用上面的函数,效果很好。

    你说你在使用时会出错

    @Entity data class MyModel(
      @PrimaryKey val e164: E164,
      val someOtherThing: String
    )
    

    如果我是你,我会考虑将上面的代码替换为:

    data class MyModel private constructor(
      @PrimaryKey val e164: String,
      val someOtherThing: String
    ) {
      companion object {
        operator fun invoke(e164: E164, someOtherThing: String) =
          MyModel(e164, someOtherThing)
      }
    }
    

    【讨论】:

    • 对,但是如果我将 Room Entity 类中的一个属性从 String 更改为 E164,那么编译器会告诉我需要提供一个类型转换器,因为它不知道如何转换E164 转换成它可以放入数据库的东西。
    • 显示完整代码以及错误消息所指的位置。
    • 这应该是注释处理器在使用类型别名时的限制。让我为你想一个解决方案。
    • 查看我的编辑。我使用String 创建了构造函数并将其设为私有,然后使用E164 创建了一个假构造函数。现在注释处理器将看到String,程序员将看到E164
    • 看起来应该可以了。没有我想要的那么优雅,但我找不到替代品,谢谢。
    【解决方案2】:

    即使我刚刚遇到这个问题,它可能已经(大部分)为 Room 修复了。在我进行了完整的清理/重新构建后,它又可以使用类型别名了。

    如果它仍然不适合你,那么我刚刚了解了 ColumnInfo.SQLiteTypeAffinity 来明确定义列的存储方式。

    以下是示例用法:

    import androidx.room.ColumnInfo.TEXT
    
    typealias FirstName = String
    
    @Entity
    class MyEntity(
        @ColumnInfo(typeAffinity = TEXT) val firstName: FirstName
    )
    

    更多信息:

    【讨论】:

      猜你喜欢
      • 2018-09-09
      • 2018-10-06
      • 2019-03-11
      • 1970-01-01
      • 1970-01-01
      • 2014-10-06
      • 1970-01-01
      • 1970-01-01
      • 2017-10-19
      相关资源
      最近更新 更多