RxJava 2 debounce : how to ignore debounce when next observable has error

1.1k views Asked by At

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?

1

There are 1 answers

3
chandra On

This may be not the best solution, but you could filter error from your api observable response in this part

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

)}
}

then your subscriber will keep getting the result. For your second question to not debounce when getting error, I have no idea how to achieve that.

Edit: To handle error from your API response, one idea is to wrap api response into another type then you can handle it properly. For example:

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

then you can use it like these:

fun getRecycleScoresByUserId(userId: Int): Observable<RecycleResponse> {
    return Observable.concatArray(
            getRecycleScoresFromDb(userId),
            getRecycleScoresFromApi(userId))
            .map<RecycleResponse> { RecycleResponse.OK(it) }
            .onErrorReturn { RecycleResponse.NotOK(it) }
}