带有 Flowable 的房间:如果数据库为空则初始化数据库
Room with Flowable: initialize database if it's empty
我有以下 @Dao
,提供 Flowable<User>
流:
@Dao
interface UsersDao {
@Query("SELECT * FROM users")
fun loadUsers(): Flowable<List<User>>
}
我希望流的订阅者在数据库发生某些变化时立即接收更新。订阅 Room 的 Flowable
我将立即获得该功能。
我想要的是:如果数据库为空,我想执行一个网络请求并将用户保存到数据库中。订阅者将自动接收刚刚发生的新更新。
现在我希望存储库的客户端不知道所有初始化逻辑:他所做的一切 - 他执行 usersRepository.loadUsers()
。所有这些魔法都应该在存储库 class:
中发生
class UsersRepository @Inject constructor(
private val api: Api,
private val db: UsersDao
) {
fun loadUsers(): Flowable<List<User>> {
...
}
}
当然我可以使用以下方法:
fun loadUsers(): Flowable<List<User>> {
return db.loadTables()
.doOnSubscribe {
if (db.getCount() == 0) {
val list = api.getTables().blockingGet()
db.insert(list)
}
}
}
但我想在不使用副作用(doOn...
运算符)的情况下构建流。我试过 composing()
但没什么用。卡在这个上面有一段时间了。
假设您的 insert() 调用是异步的并且还处理更新,您可以这样做:
fun loadUsers(): Flowable<List<User>> = userDao.getAllUsers().switchIfEmpty { api.getAllUsers().doOnNext { userDao.insert(it) } }
您还可以使用一些:
fun loadUsers(): Flowable<List<User>> = userDao.getAllUsers().flatMap { it-> if (it.isEmpty()) api.getAllUsers().doOnNext { userDao.insert(it) } else Flowable.just(it)}
建议:
你应该考虑数据过时的情况,因此你需要另辟蹊径,同时进行网络请求和数据库调用。无论哪个 observable 先完成,获取结果并显示它。更新数据库应该在网络调用完成后立即进行。
您可以应用一些条件平面图:
@Dao
interface UsersDao {
@Query("SELECT * FROM users")
fun loadUsers(): Flowable<List<User>>
@Query("SELECT COUNT(1) FROM users")
fun userCount() : Flowable<List<Integer>>
@Insert // I don't know Room btw.
fun insertUsers(List<User> users) : Flowable<Object>
}
interface RemoteUsers {
fun getUsers() : Flowable<List<User>>
}
fun getUsers() : Flowable<List<User>> {
return
db.userCount()
.take(1)
.flatMap({ counts ->
if (counts.isEmpty() || counts.get(0) == 0) {
return remote.getUsers()
.flatMap({ users -> db.insertUsers(users) })
.ignoreElements()
.andThen(db.loadUsers())
}
return db.loadUsers()
})
}
免责声明:我不了解 Room,因此请在其功能允许的情况下调整上面的示例。
我有以下 @Dao
,提供 Flowable<User>
流:
@Dao
interface UsersDao {
@Query("SELECT * FROM users")
fun loadUsers(): Flowable<List<User>>
}
我希望流的订阅者在数据库发生某些变化时立即接收更新。订阅 Room 的 Flowable
我将立即获得该功能。
我想要的是:如果数据库为空,我想执行一个网络请求并将用户保存到数据库中。订阅者将自动接收刚刚发生的新更新。
现在我希望存储库的客户端不知道所有初始化逻辑:他所做的一切 - 他执行 usersRepository.loadUsers()
。所有这些魔法都应该在存储库 class:
class UsersRepository @Inject constructor(
private val api: Api,
private val db: UsersDao
) {
fun loadUsers(): Flowable<List<User>> {
...
}
}
当然我可以使用以下方法:
fun loadUsers(): Flowable<List<User>> {
return db.loadTables()
.doOnSubscribe {
if (db.getCount() == 0) {
val list = api.getTables().blockingGet()
db.insert(list)
}
}
}
但我想在不使用副作用(doOn...
运算符)的情况下构建流。我试过 composing()
但没什么用。卡在这个上面有一段时间了。
假设您的 insert() 调用是异步的并且还处理更新,您可以这样做:
fun loadUsers(): Flowable<List<User>> = userDao.getAllUsers().switchIfEmpty { api.getAllUsers().doOnNext { userDao.insert(it) } }
您还可以使用一些:
fun loadUsers(): Flowable<List<User>> = userDao.getAllUsers().flatMap { it-> if (it.isEmpty()) api.getAllUsers().doOnNext { userDao.insert(it) } else Flowable.just(it)}
建议:
你应该考虑数据过时的情况,因此你需要另辟蹊径,同时进行网络请求和数据库调用。无论哪个 observable 先完成,获取结果并显示它。更新数据库应该在网络调用完成后立即进行。
您可以应用一些条件平面图:
@Dao
interface UsersDao {
@Query("SELECT * FROM users")
fun loadUsers(): Flowable<List<User>>
@Query("SELECT COUNT(1) FROM users")
fun userCount() : Flowable<List<Integer>>
@Insert // I don't know Room btw.
fun insertUsers(List<User> users) : Flowable<Object>
}
interface RemoteUsers {
fun getUsers() : Flowable<List<User>>
}
fun getUsers() : Flowable<List<User>> {
return
db.userCount()
.take(1)
.flatMap({ counts ->
if (counts.isEmpty() || counts.get(0) == 0) {
return remote.getUsers()
.flatMap({ users -> db.insertUsers(users) })
.ignoreElements()
.andThen(db.loadUsers())
}
return db.loadUsers()
})
}
免责声明:我不了解 Room,因此请在其功能允许的情况下调整上面的示例。