RxJava flatmap: how to check which observable emitted an error - android

I'm using RxJava's flatmap in order to execute multiple calls in sequence where one call relys on the previous call. I also need to know which observable emitted an error in the case that onError is called in order to properly implement my error handling. How do I achieve this?
Here is my code:
mSubscription = RxUtil.callObservable(mDataManager.createAccount(email, password))
.flatMap(new Func1<AuthResult, Observable<Void>>() {
#Override
public Observable<Void> call(AuthResult authResult) {
User user = new User(0, null, null, name, null, username, 0, 0);
return RxUtil.callObservable(mDataManager.createUser(authResult.getUser().getUid(), user));
}
})
.subscribe(new Subscriber<Void>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable throwable) {
try {
throw (Exception) throwable;
} catch (FirebaseAuthUserCollisionException ucException) {
getPickUpView().showError(PickUpApplication.getContext().getString(R.string.error_account_exists));
} catch (Exception exception) {
getPickUpView().showError(PickUpApplication.getContext().getString(R.string.error_account_general));
}
}
#Override
public void onNext(Void aVoid) {
getPickUpView().createAccountSuccessful(authResult);
}
});

I was thinking about this the wrong way. Is summary, I thought this was an issue that I needed to address when i didn't. RxJava will emit all errors in the onError method no matter what observable emits the error. Once onError is called the subscription is done, so the flatmap call will never take place.
In summary, all I need to do is handle my errors from both observables I call (the original and the one in the flatmap) in the same onError method.

Related

how to fetch observables in parallel, wherein only one api call has a retry logic

I want to implement a logic using RxJava in my android application, which requires three parallel api calls. Only the third api call has a retry logic. If, after having three attempts, the success is achieved then a subsequent call will be made for the fourth api, else only the result of first and second api calls will be passed on to the subscriber.
I tried to achieve this using Zip operator but then got stuck with retry logic for third api call.
Observable<String> observable1 = Observable.just("A","B");
Observable<Integer> observable2 = Observable.just(1,2);
Observable<Boolean> observable3 = Observable.just(Boolean.TRUE, Boolean.FALSE);
Observable.zip(observable1, observable2, observable3, new Function3() {
#Override
public Object apply(String s, Integer integer, Boolean aBoolean) throws Exception {
if (aBoolean==null){
alphabets3.retry(3).doOnComplete(new Action() {
#Override
public void run() throws Exception {
// the result will never be used
}
});
}
return s+integer+aBoolean;
}
}).subscribe(new Observer<Object>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Object o) {
Log.e("onNext-->", o.toString());
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
if any Observable failed in the Zip operator, Zip will fail the stream, the only way I know to achieve parallel execution and error handling with Zip, is to add onErrorResumeNext to each Observable, that map the error to a new model to deal with later .. and handling what you want to do in the zip mapping function ... for example
Obsevable.zip(
observable1.onErrorResumeNext{Observable.just(Model(it)},
observable2.onErrorResumeNext{Observable.just(Model(it)},
observable3.retryWhen {t is TimeOutException} //here you can add your retry logic
.onErrorResumeNext(t -> Observable.just(Model(t)),(m1 , m2, m3) -> Result())

Why use subscribeOn in every Observable method in RxJava

I found this when trying to understand RxJava in this example
getUserObservable method which emit some users i need to know why he put
.subscribeOn(Schedulers.io()) while he already call it on main funcion
i provided snipt for both methods
i know that subscribeOn will make the process happened on background thread , but when he called it two times is this will made any different i don't know , as i understand just calling it one time in getUsersObservable will be enough
private Observable<User> getUsersObservable() {
String[] maleUsers = new String[]{"Mark", "John", "Trump", "Obama"};
final List<User> users = new ArrayList<>();
for (String name : maleUsers) {
User user = new User();
user.setName(name);
user.setGender("male");
users.add(user);
}
return Observable
.create(new ObservableOnSubscribe<User>() {
#Override
public void subscribe(ObservableEmitter<User> emitter) throws Exception {
for (User user : users) {
if (!emitter.isDisposed()) {
emitter.onNext(user);
}
}
if (!emitter.isDisposed()) {
emitter.onComplete();
}
}
}).subscribeOn(Schedulers.io());
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_operator);
getUsersObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(new Function<User, User>() {
#Override
public User apply(User user) throws Exception {
// modifying user object by adding email address
// turning user name to uppercase
user.setEmail(String.format("%s#rxjava.wtf", user.getName()));
user.setName(user.getName().toUpperCase());
return user;
}
})
.subscribe(new Observer<User>() {
#Override
public void onSubscribe(Disposable d) {
disposable = d;
}
#Override
public void onNext(User user) {
Log.e(TAG, "onNext: " + user.getName() + ", " + user.getGender() + ", " + user.getAddress().getAddress());
}
#Override
public void onError(Throwable e) {
Log.e(TAG, "onError: " + e.getMessage());
}
#Override
public void onComplete() {
Log.e(TAG, "All users emitted!");
}
});
}
This is normally done for 2 reasons:
You see at the place, where the method is invoked, on which scheduler the observable is is subscribed on (if this is done within the method you do not know from outside).
You have the possibility to use the same method and subscribe to it on different schedulers in different places of your app.
But if you know for sure, it's always going to be the same scheduler, you can as well move the subscribeOn() into the method itself.
EDIT
I didn't see, that .subscribeOn(Schedulers.io()) is already called inside the getUsersObservable() method. It does not make sense to call it inside the method and outside, when calling the method. That seems like a bug to me. As described, above, usually .subscribeOn() is called outside the method, but you can also do it inside. Doing both makes no sense.

Using RxJava with Paho MQTT

In my Android app, I have a service which has an instance of a class(call it MQTTClient) which publishes or subscribes to an MQTT server. I want to use RxJava with Eclipse Paho Android to manage MQTT subscribe and publish operations.
I am using Single observable and SingleObserver for publishing, and Flowable observable and Observer for subscribing. But I am stuck at a point where I cannot figure out when and how to dispose of the Disposable.
Here is the Single Observable from the publish method in MQTTClient
Single<IMqttToken> pubTokenSingle = Single.create(new SingleOnSubscribe<IMqttToken>() {
#Override
public void subscribe(final SingleEmitter<IMqttToken> emitter) throws Exception {
final IMqttToken token = client.publish(topic, mqttMessage);
token.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
emitter.onSuccess(token);
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
boolean hasNetwork = isOnline(context);
if (hasNetwork && Objects.equals(((MqttException) exception).getReasonCode(),
MqttException.REASON_CODE_CLIENT_NOT_CONNECTED)) {
//connect client and retry MQTT pub
try {
//connect() is a method in MQTTClient
//connect() method also utilizes RxJava2 Single.
//Same issue of disposing a `Disposable` exists in that method as well
connect();
//call the publish method again
} catch (MqttException e) {
e.printStackTrace();
emitter.onError(e);
}
} else if (!hasNetwork) {
emitter.onError(exception);
} else {
emitter.onError(exception);
}
}
});
}
});
Here is the SingleObserver
final Disposable[] disposable = new Disposable[1];
SingleObserver<IMqttToken> pubTokenSingleObserver = new SingleObserver<IMqttToken>() {
#Override
public void onSubscribe(Disposable d) {
disposable[0] = d;
}
#Override
public void onSuccess(IMqttToken iMqttToken) {
//disposable[0].dispose();
//Planning to use the above as last resort
//Also thought of moving this to doOnSuccess
}
#Override
public void onError(Throwable e) {
//Put topic name, and mqtt message in SQLite
//disposable[0].dispose();
//Planning to use the above as last resort
//Also thought of moving this to doOnError
}
};
Someone suggested that I have a cleanup method in the concerned class which gets called when onStop is invoked.
I am concerned what would happen in case I use disposable.dispose() and the network operation is still in progress.
How do I ensure that if the operation is incomplete then at least the details persist in the SQLite DB?
I am hoping that the solution would be easily extensible for subscribing as well. If not then tell me about the possible pitfalls.
This is a learning project where I am learning RxJava2 that is why I didn't opt for RxMQTT.

RxJava re-create observable onError

So I have my form model which holds all data I want to validate and then send to the server. Let's keep it as simple as possible - isFormValid or api request should return Observable.errr(throwable) which should call onError() in the subscriber.
public void submitForm(Form form){
Observable
.just(form)
.flatMap(form->{
if(isFormValid(form))
return Observable.just(form);
else
return Observable.error(someValidationError);
})
.flatMap(form->{
Request req = new Request(form);
try{
return Observable.just(getResponseFrom(req));
}
catch(ApiException e){
return Observable.error(e)
}
}).subscribe(
new Subscriber<ResponseModel>(){
#Override
public void onComplete(){}
#Override
public void onError(Throwable t){}
#Override
public void onNext(ResponseModel model){}
}
);
}
Ok, now let's say user enters invalid data, submitForm() is called and -sure enought- onError is called in subscriber and then onComplete. The user then enters valid data and submitForm() is called again.
Now here's the problem - in the second submitForm() call nothing happens! At least flatMap Func1 and the second flatMap Func2 are not called.
Why? What am I doing wrong ? Is it an architectural flaw?

Observer.onError firing off inconsistently

I am using Retrofit to access my API as follows:
public interface UserService {
...
#POST("/user/login")
public Observable<User> register(#Body() User user);
}
Here is how I access my API:
mUserService.register(user)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<User>() {
#Override
public void onCompleted() {
....
}
#Override
public void onError(Throwable e) {
....
}
#Override
public void onNext(User user) {
....
}
});
This works perfectly well, except when there is an exception (i.e. IOException, or when connection times out), the onError method doesn't get fired, instead I get an exception on the main thread which terminates my application.
However, for some cases (such as when the API call responds with status code 400), the onError method is fired as expected.
After digging the logcat output, I have spotted this line, (not sure how I am supposed to deal with this)
rx.exceptions.OnErrorFailedException: Error occurred when trying to propagate error to Observer.onError
Can someone let me know where I am doing things wrong?
In my previous experience with RxJava the OnErrorFailedException means that an exception occurred while handling another exception in the onError method.
If you don't see stack trace of the real cause it's probably due the bug in RxJava with CompositeException (versions 0.19.2 and above) https://github.com/Netflix/RxJava/issues/1405
As a workaround try to wrap your onError code within try-catch block and log the exception. This way you will see what's the problem with your onError implementation and you will be able to solve the problem.
#Override
public void onError(Throwable e) {
try {
...
catch(Throwable e) {
// Log the exception
}
}
you can use unsafe unsafeSubscribe.
...
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.unsafeSubscribe(new Observer<User>() {
#Override
public void onCompleted() {
....
}
#Override
public void onError(Throwable e) {
....
}
#Override
public void onNext(User user) {
....
}
});
...

Categories

Resources