0

I am using RxJava in a MVP solution and I want to achieve this scenario:

  • try to get the server data and if its successful populate the view using server data

  • if its unsuccessful for any reason (no internet - server unreachable - server internal error) show the appropriate message but also populate view with the cached data.

constraints:

  • I don't wanna use any extra callback (RX can do it all)

  • I don't wanna access local repo directly from Presenter

what I tried:

in my Repo:

    override fun getRepos(userName: String, page: Int, pageSize: Int):Observable<List<Repo>> {

 return githubRemoteService.getReposList(userName, page, pageSize)
                .subscribeOn(schedulersProvider.ioThread())
                .flatMap { repos ->
                    val mappedRepos = remoteResponseMapper.mapRepoResponse(repos)
                    githubLocalService.saveRepos(mappedRepos)
                    Observable.just(mappedRepos)
                }
 .onErrorResumeNext(Observable.just(githubLocalService.getReposList(userName, page, pageSize)))
               .observeOn(schedulersProvider.mainThread())

    }

in my presenter:

githubInteractor.getRepos(userName, page, pageSize).subscribe(
            { repos ->
                 showReposInView(repos)
            },
            { error ->
                digestAndShowErrorInView(error)  //the problem is here - no error will be present here
            })

as we know when I use onErrorResumeNext, the observable source changes but the error will never be emitted.

how can I emit the error first and then emit local repo data ?

if it cant be done like this, how can I change my scenario to get the same scenario ?

Amir Ziarati
  • 14,248
  • 11
  • 47
  • 52

1 Answers1

2

You can't use onError and continue the stream. onError means a critical error occurred and the Observable ends. You can't use it.

There is a simple solution. You can wrap your result in a structure that indicates error/data. E.g.

sealed class MyData
data class Success(val data: List<Repo>) : MyData
data class Error(val t: Throwable): MyData

The you can map the successful API response to Success and in case of error (in onErrorResumeNext) you can create an Error class and use concat to continue with the local repo list.

This way you get both errors and success in onNext and you don't break the chain.

In onNext you can use when and handle error/success appropriately.

LordRaydenMK
  • 13,074
  • 5
  • 50
  • 56
  • i know I cant. never tried to do that. i am looking for a workaround to acheive that scenario. – Amir Ziarati May 27 '18 at 04:37
  • your solution will work. i actually saw that in a medium post. im hoping a more clear and neat solution if available. – Amir Ziarati May 27 '18 at 04:39
  • https://rongi.github.io/kotlin-blog/rxjava/rx/2017/08/01/error-handling-in-rxjava.html I think there must be a better way than these. – Amir Ziarati May 27 '18 at 05:18
  • @AmirZiarati what is so bad in this way? – LordRaydenMK May 27 '18 at 09:58
  • checking the object type and casting the response every where. i dont say this is bad but I say there may be a better way. if I dont find any other better approach im gonna accept this. – Amir Ziarati May 27 '18 at 11:49
  • cant I start emitting from both observable at the same time (local and remote) ? or emit the local first then I go for remote ? then If some error happend getting the remote it will be emitted. or any other way there must be some better way than wrapping your object by some class – Amir Ziarati May 27 '18 at 11:50
  • @AmirZiarati you don't cast it, the kotlin compiler does the casting for you (using `when`). For your second comment doesn't that change your logic? – LordRaydenMK May 27 '18 at 13:19
  • i know about the smart cast and all. no I just want to do some best practice. – Amir Ziarati May 28 '18 at 04:22