4

To make data accessible for offline viewing I have a data layer that first requests the data from database and secondly does a network call to get data from api (and stores it to database). F.e. say i want to get recycle scores by user id:

Datalayer:

 class RecycleScoreRepository{ 

 fun getRecycleScoresByUserId(userId: Int): Observable<RecycleScores> {
    return Observable.concatArray(
            getRecycleScoresFromDb(userId),
            getRecycleScoresFromApi(userId))}
}


object RepositoryManager {

...

fun getRecycleScoresByUserId(userId: Int): Observable<RecycleScores> {

    return recycleScoreRepository.getRecycleScoresByUserId(userId)
            //Drop DB data if we can fetch item fast enough from the API to avoid UI flickers
            .debounce(400, TimeUnit.MILLISECONDS)} ...

Presenter:

  RepositoryManager.getRecycleScoresByUserId(userId)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe({
                // do something on success
            }, {
                // do something on error
            })

So my presenter is subscribing to the Repository to getRecycleScoresByUserId. I am using the debounce operator to make sure that in case the api call is fast enough that i am not setting returned values twice on ui as to prevent ui flickering. But now what happens is that when the database successfully returns me some recycleScores but for some reason api request response with an error that the subscriber in the presenter only receives an error and not the observable with values from the database.

How can I make sure the database's observable is received by subscribers and not being debounced when api call returns an error?

4

1 回答 1

2

这可能不是最好的解决方案,但您可以在这部分从您的 api observable 响应中过滤错误

fun getRecycleScoresByUserId(userId: Int): Observable<RecycleScores> {
    return Observable.concatArray(
            getRecycleScoresFromDb(userId),
            getRecycleScoresFromApi(userId)                
                .materialize()
                .filter{ !it.isOnError }
                .dematerialize<RecycleScores>()

)}
}

那么您的订阅者将不断获得结果。对于您的第二个问题在出现错误时不反弹,我不知道如何实现这一点。

编辑:要处理来自 API 响应的错误,一个想法是将 api 响应包装成另一种类型,然后您可以正确处理它。例如:

sealed class RecycleResponse {
    class OK(val score: RecycleScore) : RecycleResponse()
    class NotOK(val error: Exception) : RecycleResponse()
}

那么你可以像这样使用它:

fun getRecycleScoresByUserId(userId: Int): Observable<RecycleResponse> {
    return Observable.concatArray(
            getRecycleScoresFromDb(userId),
            getRecycleScoresFromApi(userId))
            .map<RecycleResponse> { RecycleResponse.OK(it) }
            .onErrorReturn { RecycleResponse.NotOK(it) }
}
于 2017-09-01T14:31:29.267 回答