Android 房间 DAO 接口不适用于继承
Posted
技术标签:
【中文标题】Android 房间 DAO 接口不适用于继承【英文标题】:Android room DAO interface does not work with inheritance 【发布时间】:2019-03-14 23:40:49 【问题描述】:interface Marker<T : BaseFoo>
fun getSpecialFoo(): List<T>
@Dao
interface FooDao: Marker<Foo>
@Query("SELECT * FROM foo WHERE bar = :bar")
fun get(bar: Int): List<Foo>
@Transaction
override fun getSpecialFoo(): List<Foo>
return get(1)
这会导致
抽象 DAO 方法必须使用以下注释中的一个且仅一个注释:Insert、Delete、Query、Update、RawQuery
但是,Marker
未标记为 @Dao
和 FooDao
已覆盖 getSpecialFoo
。为什么仍然显示此错误?
我需要Marker
,因为我需要一个具有一些方法的通用 DAO。有没有办法解决这个问题?
我能想到的唯一方法是将 dao 标记为 Any
并强制转换类型运行时或为 DAO 构建一个包装器。
【问题讨论】:
@IntelliJAmiya 这是我在 *** 上输入的一个错字。已编辑。 【参考方案1】:你可以解决它。
问题不在于房间限制,而在于 kotlin 实现本身。您正在使用泛型集合方法,默认情况下处理为 List<? extends T>
java 实现,但被覆盖的方法具有 List<Foo>
返回类型。房间生成器匹配方法签名,找不到具有相同签名的实现方法,所以你得到
abstract DAO 方法必须用一个且只有一个注释 以下注释
解决方法就是在@JvmSuppressWildcards
的接口中注解方法参数:
fun getSpecialFoo(): List<@JvmSuppressWildcards T>
【讨论】:
最佳答案。如果这是一个直接而简单的答案,我不会为 DAO 编写包装器。 提示:如果你的 BaseDao 有 @Transaction 注解的方法,那么你需要让你的ConcreteClassDao
不是一个接口,而是一个抽象类。
请注意,如果您的非 Room DAO 接口包含 suspend fun foos(): List<@JvmSuppressWildcards Foo>
,则生成的 Room DAO 将在生成的 Java 方法上显示 lint 错误:com.example.FooDao_Impl
中的 foos(Continuation<? super List<Foo>>)
与 @987654329 冲突@在com.example.FooDao
;两种方法都有相同的擦除,但都没有覆盖另一个。这可能不是问题。无论如何,Java List<E>
与 Kotlin 的 List<out E>
(带有抑制通配符)不同。请在此处发表评论,或者如果您认为不同,请回答!【参考方案2】:
这似乎是 Room 库的限制。你可以像下面这样解决它。
@Dao
interface FooDao
@Query("SELECT * FROM foo WHERE bar = :bar")
fun get(bar: Int): List<Foo>
@Transaction
fun getSpecialFoo(): List<Foo>
return get(1)
fun FooDao.wrapper(): Marker<Foo>
return Wrapper(this)
private class Wrapper(private val dao: FooDao): Marker<Foo>
override fun getSpecialFoo() = dao.getSpecialFoo()
当您需要Marker<Foo>
时,您可以通过wrapper()
创建一个包装器,该包装器通过dao
实现Marker<Foo>
。
【讨论】:
一种变通解决方案,但不如使用@JvmSuppressWildcards
以上是关于Android 房间 DAO 接口不适用于继承的主要内容,如果未能解决你的问题,请参考以下文章
Forge 数据可视化不适用于 Revit 房间 [ITA]