1

When the Retrofit Call does not succeed ( for example because no Internet), is called as expected the RXJava Callback onError, where I have a Snackbar with a setAction() Listener indicated with an intuitive String "Retry" where I should pass a command to start again the network call. I could restart the class where I am inside calling it NameActivity(), but this look terrible.Which command I can pass inside the Snackbar listener to restart the below code?

 MyViewModel!!.getPost("132")
            ?.subscribeOn(schedulerProvider!!.io())
            ?.observeOn(schedulerProvider!!.ui())
            ?.doOnNext {
                run {
                    spinner.setVisibility(View.VISIBLE)
                }
            }

            ?.subscribe(object : FlowableSubscriber<List<Post>> {
                override fun onError(t: Throwable?) {
                    spinner.setVisibility(View.GONE)

                    spinner.visibility
                    Snackbar.make(view.findViewById(R.id.linearLayout), "Check Internet Connection!", Snackbar.LENGTH_INDEFINITE)
                            .setAction("Retry", {})//HERE THE COMMAND SHOULD PASS
                            .show();

                }

                override fun onComplete() {
                    Log.d("TAG", "onComplete: ")
                }

                override fun onSubscribe(s: Subscription) {
                    s.request(Long.MAX_VALUE);

                }

                override fun onNext(posts: List<Post>?) {
                    spinner.setVisibility(View.GONE)

                    posts?.let { viewAdapter.setTitleData(it) }

                }
            })
}
Drocchio
  • 383
  • 4
  • 21

1 Answers1

1

If you want to show the snackbar right away when your call fails, you have to call the subscription again. You could refactor your code as follows:

  1. Place your Rx code inside a method. e.g. doNetworkCall().
  2. Create a separate method to handle your errors. e.g. handleError(t: Throwable).
  3. Inside that method you can make your Snackbar appear, and call the doNetworkCall() method once the user taps the retry action.

Example:

fun doNetworkCall() {
    MyViewModel!!.getPost("132")
            ?.subscribeOn(schedulerProvider!!.io())
            ?.observeOn(schedulerProvider!!.ui())
            // The rest of the code here was removed for brevity.
             ?.subscribe(object : FlowableSubscriber<List<Post>> {
                override fun onError(t: Throwable?) {
                    spinner.setVisibility(View.GONE)
                    spinner.visibility

                    handleError(t) // Call the method here.
                }
            // The rest of the code here was removed for brevity.
}

fun handleError(t: Throwable?) {
    // Here you can also check the type of the error, and perhaps even change the snackbar action depending on it.
    Snackbar.make(view.findViewById(R.id.linearLayout), "Check Internet Connection!", Snackbar.LENGTH_INDEFINITE)
            .setAction("Retry", doNetworkCall()) // Set the retry action to call the doNetworkCall() method again.
            .show()
}

You could also use automatic retries before you prompt anything to the user. That can be achieved by using the Rx retry operator. If your network call fails, it'll automatically subscribe again for a given number of tries.

As stated on the ReactiveX docs:

  • One variant of retry takes no parameters. It will continue to resubscribe to and mirror the source Observable no matter how many onError notifications it receives.

  • Another variant of retry takes a single parameter: a count of the number of times it should try to resubscribe to the source Observable when it encounters errors. If this count is exceeded, retry will not attempt to resubscribe again and will instead pass the latest onError notification to its observers.

  • A third variant of retry takes a predicate function as a parameter. You write this function to accept two arguments: an Integer count of how many retries have taken place thusfar, and a Throwable indicating the error that caused the onError notification. This function returns a Boolean to indicate whether or not retry should resubscribe to and mirror the source Observable. If it does not, then retry passes the latest onError notification to its observers.

Mauker
  • 11,237
  • 7
  • 58
  • 76
  • Thanks.Well `retry` operator does not fit my use case because cannot be called from inside `SnackBar` Listener, so I would like to implement the solution you mention, but how can I implement point 2 if onError get called inside the Subscriber Callbacks and not in a separate method, in other words is inside the `doNetworkCall()`you suggest at point one – Drocchio Aug 29 '18 at 18:00
  • You can create a method outside `doNetworkCall()` to handle the errors, and call this method inside the Rx's `onError`. – Mauker Aug 29 '18 at 18:02
  • first of all if I wrap all the code I published I have to inject also the View so that would be `fun doNetworkCall(view:View)` because I have instance of the view for the `SnackBar` and `ProgressBar`, but the central problem is how I can isolate `onError` as a method? I am trying but as expected does not work because onError should go into a subscription to an Observable that is basically all the method `doNetworkCall(view:view)` I mean `Observable.subscribe(//here are called the 4 rxjava callBacks, and cannot isolate OnError apart!)` – Drocchio Aug 29 '18 at 18:10
  • amazing @Mauker is working thank you very much. Response accepted – Drocchio Aug 29 '18 at 18:22