Reputation: 161
TL;DR version
I'd like to have a method whose returning signature is LiveData<User>
, in which User
is an interface. And the implementation returns a LiveData<UserEntity>
in which UserEntity
is a concrete class that extends User
. Like following:
fun getUser(id: String): LiveData<User> {
// for brevity
return LiveData<UserEntity>() // actual code will retrieve data from db
}
The compiler complains return type not match error
TL; version
I'm reading the Jetpack guide. In it, they designed a DataRepository
class which can retrive data from either DB or WebService, as shown in this graph:
And they claim that
Notice that each component depends only on the component one level below it.
It's an appealing design, I actually tried to replicate it in my own project. However, I found WebService
inevitably depends on Room
, because it's method getUser()
returns a LiveData
of User
, which is a Room Entity.
This issue might not break the app, but it's contradicting the fundamental design of the"separation of concerns" principle, and is aesthetically ugly IMHO.
My question is: are there any workaround? I've tried to refactor User
as an interface and implemented an UserEntity
class that extends it. Shown below:
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
}
Note I have to return UserEntity
intead of User
, because Room doesn't know how to construct an interface.
Here is the problem: the following code won't compile:
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)
}
The error indicates
data type mismatch: LiveData<User> vs. LiveData<UserEntity>
Upvotes: 3
Views: 385
Reputation: 3518
The above code won't work, as you can't expect a function to return multiple data types. I recommend using one User class which merges both Room and GSON mapping.
@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,
)
You can get rid of your UserEntity class and use the above as the DTO for both API and DB repository.
Upvotes: 2