从 Room 返回接口的 LiveData?

3

简洁版

我想要一个返回签名为LiveData<User>的方法,其中User是一个接口。实现应该返回LiveData<UserEntity>,而UserEntity是一个继承了User的具体类。像下面这样:
fun getUser(id: String): LiveData<User> {
    // for brevity
    return LiveData<UserEntity>() // actual code will retrieve data from db
}

编译器报错了,显示“返回类型不匹配错误”。

简短版

我正在阅读Jetpack指南。其中,他们设计了一个DataRepository类,可以从数据库或Web服务中检索数据,如下图所示: Jetpack指南的应用程序结构 并且他们声称:

请注意,每个组件仅依赖于其下一级组件。

这是一个有吸引力的设计,我实际上尝试在自己的项目中复制它。 然而,我发现WebService无法避免依赖于Room,因为它的方法getUser()返回UserLiveData,它是一个Room实体

这个问题可能不会破坏应用程序,但它与“关注点分离”原则的基本设计相矛盾,并且在我看来不美观。

我的问题是:是否有任何解决方法? 我已尝试将User重构为接口,并实现一个扩展它的UserEntity类。如下所示:

interface User {
    val id: String
    val name: String
    val lastName: String
}

@Entity(tableName="users")
data class UserEntity(
    override val id: String
    override val name: String
    override val lastName: String) : User

@Dao
interface UserDao() {
    @Query("SELECT * FROM users where id = :id")
    fun getUser(id: String): LiveData<UserEntity> // UserEntity instead of User, because Room doesn't know how to construct an interface
}

请注意,我需要返回UserEntity而不是User,因为Room不知道如何构造一个接口。
问题在于以下代码无法编译:
interface DataRepository {
    fun getUser(id: String): LiveData<User>
}
class DbRepository : DataRepository {
    // ... init db connection/userDao ...
    override fun getUser(id: String): LiveData<User> = userDao.getUser(id)
}

错误提示表示数据类型不匹配:LiveData<User> 与 LiveData<UserEntity>。
1个回答

2
上面的代码不会起作用,因为你不能期望一个函数返回多个数据类型。我建议使用一个用户类,将房间和GSON映射合并在一起。
@Entity(tableName="users")
data class Users(
  @PrimaryKey           // Room annotation
  @SerializedName("id") // Gson annotation
  val id: String,
  @ColumnInfo(name = "name") 
  @SerializedName("name")   
  val name: String,
  @ColumnInfo(name = "lastName") 
  @SerializedName("lastName")    
  val lastName: String,
)

你可以放弃使用UserEntity类,使用上述DTO来代替API和DB repository。

但这仍然无法消除 WebService 对 Room 的依赖,不是吗?这样我就无法在没有 Room 的情况下对 WebService 进行单元测试。(以及其他许多相互依赖的缺点) - victl
@victl 个人认为这不会影响您的单元测试。这只是一个数据类,您的单元测试将针对您的 Web 服务仓库和本地存储库进行。 - Badhrinath Canessane
1
@victl 这是谷歌的示例,遵循了我建议的相同方法。https://github.com/android/architecture-components-samples/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/vo/User.kt - Badhrinath Canessane

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接