0
votes

We are trying to handle an error when I receive a response from a back-end. If the response is successful we are starting a new activity, on the other hand if the response is not successful we invoke the onError method.

We have the feeling we are not handling properly the lifecycle due we open a new activity, our subscription gets unsubscribed, so we do not dismiss the dialog properly. Should we store a variable in subscriber inner class to ask for that in onComplete, and in that method start the new activity? Or this aproximation is good enough?

Subscriber<BackendResponse> subscriber = new Subscriber<BackendResponse>() {
        @Override
        public void onCompleted() {
            progressDialog.dismiss();
        }

        @Override
        public void onError(Throwable exception) {
            progressDialog.dismiss();
            SnackbarNotification.show(coordinatorLayout, "Error");
        }

        @Override
        public void onNext(BackendResponse backendResponse) {
            if (backendResponse.getSuccess()){
                startActivity(new Intent(LoginActivity.this, HomeActivity.class));
            } else {
                onError(new Exception("Launch onError"));
            }
        }
    };

Moreover, are we handling in the correct way the onError flow? We know that invoking the onError from onNext it will cause to call on Error and after that call onComplete. Should we unsubscribe the subscriber on the onError method?

We have found a wrapper for the subscriber:

public abstract class DefaultSubscriber<T> extends Subscriber<T> {
    protected T result;

    @Override
    public void onCompleted() {
        onSuccess(result);
    }

    @Override
    public void onError(Throwable e) {
        CustomLog.e("onError", e.getMessage());
        onFailure(e);
    }

    @Override
    public void onNext(T t) {
        result = t;
    }

    protected abstract void onSuccess(T t);

    protected abstract void onFailure(Throwable exception);
}

Doing so, we store the result provided by onNext in a member variable. Once the stream has been finished (only one iteration) we call onSuccess (result) inside onCompleted. On the other hand we handle the onError in onFailure method. What do you think about that? Are we missing something?

1

1 Answers

2
votes

So first of all I wouldn't check for the backendResponse.getSuccess() in the subscriber. I would prefer to add a step prior to it e.g. with a .flatMap like:

//your observable
.flatMap(backendResponse - > {
   if (backendResponse.getSuccess()){
     return just(backendResponse);
   }else{
     return Observable.error(new Exception("Launch onError"));
   }
})

Furthermore I would subscribe like:

.flatMap (  ...  ) // the flatmap above
.subscribe(new Subscriber<BackendResponse>() {
        @Override
        public void onCompleted() {
        }

        @Override
        public void onError(Throwable exception) {
            progressDialog.dismiss();
            SnackbarNotification.show(coordinatorLayout, "Error");
        }

        @Override
        public void onNext(BackendResponse backendResponse) {
            progressDialog.dismiss();
            startActivity(new Intent(LoginActivity.this, HomeActivity.class));
        }
    });

Would that create a glitch or be what you want? I assumed that you will receive only one BackendResponse event.

However if you need to keep your logic only when the observable completes, then I see two solutions:

  • move the progress dialog logic in your HomeActivity
  • extend the lifecycle of your subscription (careful not to leak subscriptions)