Using RxJava with Paho MQTT - android

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.

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())

RxJava flatmap: how to check which observable emitted an error

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.

How to make a HTTP request to check a content type with RxJava 2?

I need to get the content type from a specific URL. I know that we can do it by simply coding:
URL url = new URL("https://someurl.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("HEAD"); // Request Method: GET/POST/UPDATE...
connection.connect();
String contentType = connection.getContentType();
Since this blocks the UI thread (a synchronous operation), how to make a HTTP request using RxJava 2 on Android?
Notes:
I don't want to make this using the AsyncTask. Why?
This is related to RxJava 2 and not version 1.
Give me a clear, simple and concise example if you can.
Use RxJava just operator to leave main thread and continue the process on thread from computation scheduler and then use flatMap to make http call and find content type, network calls should run on threads from IO scheduler and finally observe on main thread and subscribe to result.
Observable.just(1).subscribeOn(Schedulers.computation())
.flatMap(dummyValueOne -> {
return Observable.just(getContentType).subscribeOn(Schedulers.io());
}).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<String>() {
#Override
public void accept(String contentType) throws Exception {
//do nextsteps with contentType, you can even update UI here as it runs on main thread
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
Log.e("GetContentType", "exception getting contentType", throwable);
}
}));
You can use a Callable. Here's an example,
Observable.fromCallable((Callable<Object>) () -> {
// do stuff
return object;
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Object>() {
#Override
public void onSubscribe(#NonNull Disposable d) {
// so that this can be properly disposed in onDestroy()
compositeDisposable.add(d);
}
#Override
public void onNext(#NonNull Object object) {
// do stuff with the result
}
#Override
public void onError(#NonNull Throwable e) {
}
#Override
public void onComplete() {
}
});

Retrofit 2 + RxJava cancel/unsubscribe

I am performing a network request where I send files and a message.
I would like to have an option to cancel current request. I have found two similar questions and both suggests that observable.subscribe(Observer) returns Subscription object which has method unsubscribe().
Here is the first one
And the second one
In my case, I use observable.subscribe(Observer) which is void. Here is my code:
Observable<MessengerRaw> observable = mModel.sendMessage(message, companion, description, multiParts);
observable.subscribe(new Observer<MessengerRaw>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(MessengerRaw value) {
if (getView() != null) {
((MessengerActivity) getView()).resetMessegeView();
((MessengerActivity) getView()).updateMessageList();
}
}
#Override
public void onError(Throwable e) {
getData().remove(0);
if (getView() != null) {
((MessengerActivity) getView()).updateMessageList();
}
}
#Override
public void onComplete() {
hideProgress();
}
});
So how do I unsubscribe/cancel my request?
Thank you.
In RxJava2, you can get Disposable object in onSubscribe callback method of oserver, which you can use to dispose subscription.
In RXJava You must use subscriptions for unsubscribe
private Subscription mSubscription;
/.../
Observable<MessengerRaw> observable = mModel.sendMessage(message, companion, description, multiParts);
Subscription subscription = observable.subscribe(new Observer<MessengerRaw>() {/.../});
When you want to unsubscribe you can call
if(!subscription.isUnsubscribed()){
subscription.unsubscribe();
}
In RXJava 2 observable.subscribe(new Observer<MessengerRaw>() {/.../}); returns Disposable object, you can call dispose();

Stripe creates token on Android

We are trying to create a stripe token from a credit card on our android application, but when we call stripe.createToken it does nothing, it doesn't enter onSuccess nor onError methods in the listener. Our code is the following:
private void getStripeToken(Card card) {
Stripe stripe = null;
try {
stripe = new Stripe(getApplicationContext(), getString(R.string.stripe_public_key));
} catch (AuthenticationException e) {
e.printStackTrace();
return;
}
stripe.createToken(card, new TokenCallback() {
#Override
public void onError(Exception error) {
stripeError = error.getLocalizedMessage();
}
#Override
public void onSuccess(Token token) {
stripeToken = token;
}
});
}
When getStripeToken is finished, stripeError and stripeToken are null. Where are the mistake? Thanks
At the end of your getStripeToken method, the values are going to be unchanged because createToken is an asynchronous action -- that's why you have to give it a callback.
So, if you use createToken, you must be on the UI thread (because it uses a AsyncTask to make that call, and you should expect your values to be updated whenever the network call is done.
If you want the values to be updated at the end of your method call, use createTokenSynchronous, but be sure to only do so off the main thread.

Categories

Resources