具有 Room 持久性库的 Kotlin 代表
Kotlin delegates with Room persistence lib
我目前正在使用 Kotlin 开发一个新的 android 应用程序。我尝试为数据存储实现 Room,但我没有让它与 Kotlin 委托一起工作。
我创建了一个 Identifier
委托,以确保 id 在初始化后不被更改。代表看起来像这样:
class Identifier: ReadWriteProperty<Any?, Long> {
private var currentValue = -1L
override fun getValue(thisRef: Any?, property: KProperty<*>): Long {
if (currentValue == -1L) throw IllegalStateException("${property.name} is not initialized.")
return currentValue
}
override fun setValue(thisRef: Any?, property KProperty<*>, value: Long) {
if (currentValue != -1L) throw IllegalStateException("${property.name} can not be changed.")
currentValue = value
}
}
我的实体 class 看起来像这样:
@Entity
class Sample {
@delegate:PrimaryKey(autoGenerate = true)
var id by Identifier()
}
当我尝试启动应用程序时,kapt 给我以下错误消息:
Cannot figure out how to save this field into database. You can consider adding a type converter for it.
private final com.myapp.persistence.delegates.Identifier id$delegate = null;
我是否可以在不为每个代表编写 TypeConverter
的情况下以某种方式让它工作?
不幸的是,没有 - Room 默认情况下为实体中定义的每个字段创建一个列,当我们使用 delegate
时,我们得到如下生成的代码:
@PrimaryKey(autoGenerate = true)
@NotNull
private final Identifier id$delegate = new Identifier();
public final long getId() {
return this.id$delegate.getValue(this, $$delegatedProperties[0]);
}
public final void setId(long var1) {
this.id$delegate.setValue(this, $$delegatedProperties[0], var1);
}
这就是 Room 尝试为 Identifier id$delegate
创建列的原因。
但是,如果您只想确保 id
在对象初始化后不发生变化,您根本不需要委托,只需将变量标记为 final
并将其放在构造函数中即可,例如:
@Entity
data class Sample(
@PrimaryKey(autoGenerate = true)
val id: Long
)
我对以下代码有类似的问题:
data class ForecastItem(
val city: String,
val time: Long,
val temp: Int,
val tempMax: Int,
val tempMin: Int,
val icon: String
) {
val formattedTime: String by lazy {
val date = Date(this.time * 1000L)
val dateFormat = SimpleDateFormat("E HH:mm")
dateFormat.timeZone = TimeZone.getTimeZone("GMT+1")
dateFormat.format(date)
}
}
在这种情况下,由于使用 formattedTime 进行委托,我遇到了与您相同的错误:
Cannot figure out how to save this field into database. You can consider adding a type converter for it.
就我而言,我最终用函数替换了委托。它不一样,但它对我有用。我不确定这是否真的是设计解决方案的最佳方式,但我希望它能帮助遇到类似问题的任何人。
fun getFormattedTime(): String {
val date = Date(this.time * 1000L)
val dateFormat = SimpleDateFormat("E HH:mm")
dateFormat.timeZone = TimeZone.getTimeZone("GMT+1")
return dateFormat.format(date)
}
使用@delegate:Ignore
.
我的实体对象和 ... by lazy
属性也有类似的问题。
例如:
var name: String = "Alice"
val greeting: String by lazy { "Hi $name" }
这里的问题是房间 "cannot figure out how to save this field into database"。我尝试添加“@Ignore”,但收到一条 lint 消息,内容为 "This annotation is not applicable to target 'member property with delegate'."
事实证明,在这种情况下正确的注释是 @delegate:Ignore
。
解法:
var name: String = "Alice"
@delegate:Ignore
val greeting: String by lazy { "Hi $name" }
我目前正在使用 Kotlin 开发一个新的 android 应用程序。我尝试为数据存储实现 Room,但我没有让它与 Kotlin 委托一起工作。
我创建了一个 Identifier
委托,以确保 id 在初始化后不被更改。代表看起来像这样:
class Identifier: ReadWriteProperty<Any?, Long> {
private var currentValue = -1L
override fun getValue(thisRef: Any?, property: KProperty<*>): Long {
if (currentValue == -1L) throw IllegalStateException("${property.name} is not initialized.")
return currentValue
}
override fun setValue(thisRef: Any?, property KProperty<*>, value: Long) {
if (currentValue != -1L) throw IllegalStateException("${property.name} can not be changed.")
currentValue = value
}
}
我的实体 class 看起来像这样:
@Entity
class Sample {
@delegate:PrimaryKey(autoGenerate = true)
var id by Identifier()
}
当我尝试启动应用程序时,kapt 给我以下错误消息:
Cannot figure out how to save this field into database. You can consider adding a type converter for it.
private final com.myapp.persistence.delegates.Identifier id$delegate = null;
我是否可以在不为每个代表编写 TypeConverter
的情况下以某种方式让它工作?
不幸的是,没有 - Room 默认情况下为实体中定义的每个字段创建一个列,当我们使用 delegate
时,我们得到如下生成的代码:
@PrimaryKey(autoGenerate = true)
@NotNull
private final Identifier id$delegate = new Identifier();
public final long getId() {
return this.id$delegate.getValue(this, $$delegatedProperties[0]);
}
public final void setId(long var1) {
this.id$delegate.setValue(this, $$delegatedProperties[0], var1);
}
这就是 Room 尝试为 Identifier id$delegate
创建列的原因。
但是,如果您只想确保 id
在对象初始化后不发生变化,您根本不需要委托,只需将变量标记为 final
并将其放在构造函数中即可,例如:
@Entity
data class Sample(
@PrimaryKey(autoGenerate = true)
val id: Long
)
我对以下代码有类似的问题:
data class ForecastItem(
val city: String,
val time: Long,
val temp: Int,
val tempMax: Int,
val tempMin: Int,
val icon: String
) {
val formattedTime: String by lazy {
val date = Date(this.time * 1000L)
val dateFormat = SimpleDateFormat("E HH:mm")
dateFormat.timeZone = TimeZone.getTimeZone("GMT+1")
dateFormat.format(date)
}
}
在这种情况下,由于使用 formattedTime 进行委托,我遇到了与您相同的错误:
Cannot figure out how to save this field into database. You can consider adding a type converter for it.
就我而言,我最终用函数替换了委托。它不一样,但它对我有用。我不确定这是否真的是设计解决方案的最佳方式,但我希望它能帮助遇到类似问题的任何人。
fun getFormattedTime(): String {
val date = Date(this.time * 1000L)
val dateFormat = SimpleDateFormat("E HH:mm")
dateFormat.timeZone = TimeZone.getTimeZone("GMT+1")
return dateFormat.format(date)
}
使用@delegate:Ignore
.
我的实体对象和 ... by lazy
属性也有类似的问题。
例如:
var name: String = "Alice"
val greeting: String by lazy { "Hi $name" }
这里的问题是房间 "cannot figure out how to save this field into database"。我尝试添加“@Ignore”,但收到一条 lint 消息,内容为 "This annotation is not applicable to target 'member property with delegate'."
事实证明,在这种情况下正确的注释是 @delegate:Ignore
。
解法:
var name: String = "Alice"
@delegate:Ignore
val greeting: String by lazy { "Hi $name" }