我想将我的rxJava代码转换为Kotlin CoRoutine。
下面是代码进行api和db调用,并将数据返回到UI,无论是什么先发生。让我们说一下DB响应是否恰好比api更快。在那种情况下,api响应将继续,直到它接收到与db同步的数据,尽管它可能早先完成了UI更新。
我该怎么办?
class MoviesRepository @Inject constructor(val apiInterface: ApiInterface,
val MoviesDao: MoviesDao) {
fun getMovies(): Observable<List<Movie>> {
val observableFromApi = getMoviesFromApi()
val observableFromDb = getMoviesFromDb()
return Observable.concatArrayEager(observableFromApi, observableFromDb)
}
fun getMoviesFromApi(): Observable<List<Movie>> {
return apiInterface.getMovies()
.doOnNext { it ->
it.data?.let { it1 -> MoviesDao.insertAllMovies(it1) }
println("Size of Movies from API %d", it.data?.size)
}
.map({ r -> r.data })
}
fun getMoviesFromDb(): Observable<List<Movie>> {
return MoviesDao.queryMovies()
.toObservable()
.doOnNext {
//Print log it.size :)
}
}
}
作为第一步,你应该为你的suspend fun
和ApiInterface
电话创建MovieDao
s。如果他们有一些基于回调的API,您可以关注these official instructions。
你现在应该有
suspend fun ApiInterface.suspendGetMovies(): List<Movie>
和
suspend fun MoviesDao.suspendQueryMovies(): List<Movie>
现在你可以编写这段代码:
launch(UI) {
val fromNetwork = async(UI) { apiInterface.suspendGetMovies() }
val fromDb = async(UI) { MoviesDao.suspendQueryMovies() }
select<List<Movie>> {
fromNetwork.onAwait { it }
fromDb.onAwait { it }
}.also { movies ->
// act on the movies
}
}
重点是select
调用,它将同时等待Deferred
s并对首先完成的那个进行操作。
如果您想确保根据网络的结果采取行动,则需要更多代码,例如:
val action = { movies: List<Movie> ->
// act on the returned movie list
}
var gotNetworkResult = false
select<List<Movie>> {
fromNetwork.onAwait { gotNetworkResult = true; it }
fromDb.onAwait { it }
}.also(action)
if (!gotNetworkResult) {
action(fromNetwork.await())
}
只有当它们在网络结果之前进入时,此代码才会对数据结果起作用,它将在所有情况下处理。
沿着这些方向的东西应该有效:
data class Result(val fromApi: ???, val fromDB: ???)
fun getMovies(): Result {
val apiRes = getMoviesFromApiAsync()
val dbRes = getMoviesFromDbAsync()
return Result(apiRes.await(), dbRes.await())
}
fun getMoviesFromApiAsync() = async {
return apiInterface.getMovies()
.doOnNext { it ->
it.data?.let { it1 -> MoviesDao.insertAllMovies(it1) }
println("Size of Movies from API %d", it.data?.size)
}
.map({ r -> r.data })
}
fun getMoviesFromDbAsync() = async {
return MoviesDao.queryMovies()
}
我不知道你要回来的是什么,所以我只是把???
改为。