RxJava call disposable dispose() - android

I am using rxjava with retrofit. In the following code the subscribeOn() and observeOn() keeps running. The App terminates and launched by itself continuously.
disposable = api.getUsers("135")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
users -> showResult(users)
})
If I dispose right after the above it won't fetch complete data. So my question is when to dispose dispoable or how to know when subscribeOn() and observeOn() has completed it's task.

either you can dispose in onDestroy() of your Activity.
or you can use DisposableSingleObserver for good , like this :
Disposable disposable = yourApi.subscribeWith(new DisposableSingleObserver<List<String>>() {
#Override
public void onSuccess(List<String> values) {
// work with the resulting values
}
#Override
public void onError(Throwable e) {
// handle the error case
}
});
and then after you use the result (in this example case when you no longer need the values(api response) you can call dispose
disposable.dispose();
best place to dispose an observer will be in onDestory() , this will be the place where you no longer will be needing api result:
protected void onDestroy(){
super.onDestroy();
disposable.dispose();
}

Related

How to subscribe and unsubscribe or cancel an rxjava observable

I am new in RxJava and trying to update my asyncTask works to RxJava. As a first try I have done the following codes:
public class MainActivity extends AppCompatActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
doSomeWork();
}
private String funcCallServerGet()
{
//Some code to call a HttpClient Get method & return a response string
//this is the method which previously i used to call inside asynctask doInbackground method
}
private void doSomeWork() {
getSingleObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(getSingleObserver()) ;
}
private Single<String> getSingleObservable()
{
return Single.create(new SingleOnSubscribe<String>() {
#Override
public void subscribe(SingleEmitter<String> emitter) throws Exception {
if(!emitter.isDisposed()) {
String strRxResponse = funcCallServerGet();
emitter.onSuccess(strRxResponse);
}
}
});
}
private SingleObserver<String> getSingleObserver()
{
return new SingleObserver<String>() {
#Override
public void onSubscribe(Disposable d) {
Log.d(TAG, " onSubscribe getSingleObserver: " + d.isDisposed()); }
#Override
public void onSuccess(String value) {
Log.d(TAG, " onNext : value : " + value); }
#Override
public void onError(Throwable e) {
Log.d(TAG, " onError : " + e.getMessage()); }
};
}
}
But I have some confusions:
Why am I getting false in onSubscribe() of SingleObserver getSingleObserver() .
How do I unsubscribe or cancel the observable/observer when activities onStop() is called.
Also, what really happens when screen oriantation. Does the observable get unsubscribed automatically or it continues its work ? what to do for the device rotation ?
Why am I getting false in onSubscribe() of SingleObserver getSingleObserver() .
You're currently logging whether the disposable is disposed within the onSubscribe method. At this point the disposable hasn't been disposed yet.
How do I unsubscribe or cancel the observable/observer when activities onStop() is called.
Rather than use a SingleObserver you could use the subscribe method which returns a disposable. With this you could either manage the disposable directly or use a CompositeDisposable. You would then call the dispose method on that disposable, with CompositeDisposable this is achieved by calling clear()
private final CompositeDisposable disposables = new CompositeDisposable();
#Override
protected void onStart() {
super.onStart();
disposables.add(getSingleObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(value -> {
Log.d(TAG, " onSuccess: " + value);
}, error -> {
Log.e(TAG, " onError", error);
}
)
);
}
#Override
protected void onStop() {
disposables.clear();
super.onStop();
}
Also, what really happens when screen oriantation. Does the observable get unsubscribed automatically or it continues its work ? what to do for the device rotation ?
By default no automatic management of the observable occurs, it's your responsibility to manage it. In your example code when the device rotates you will receive another call to onCreate, here you're scheduling the work to be executed again, work that was scheduled before rotation could still be running, so you could end up leaking the old activity and receiving a callback when the work succeeds or fails - in this case you'd see a log statement.
There are some tools that provide automatic observable management, though you should read the authors article about some of the issues that exist with this approach.
https://blog.danlew.net/2017/08/02/why-not-rxlifecycle/
https://github.com/trello/RxLifecycle
https://github.com/uber/AutoDispose
Another option for you could be to look at the new Architecture Components library, specifically ViewModel and LiveData. This will simplify what you need to do with respect to subscription management and configuration changes.

Using RxJava and EventBus to send an event back to the activity/fragment

Android Studio 3.2 Canary 8
com.squareup:otto:1.3.8
io.reactivex:rxjava:1.3.7
kotlin 1.2.31
I am trying to send an event back to my Activity using the otto EventBus.
However, I am using RxJava to perform some background work and need the event to be sent after the first one completes. However, after post the event. The activity never receives it.
This event must do this on the main thread. The RxJava is on the IO thread. I am not sure what is the best way to do this:
Here is my code for the interactor that does the RxJava and EventBus post
class Interactors(private val eventBus: Bus) {
fun transmitMessage(): Completable {
return insertTransmission()
.andThen(onTransmissionChanged()) /* Send event to the activity */
.andThen(requestTransmission())
}
private fun insertTransmission(): Completable {
return Completable.fromCallable {
Thread.sleep(4000)
System.out.println("insertTransmission doing some long operation")
}
}
private fun requestTransmission(): Completable {
return Completable.fromCallable {
Thread.sleep(2000)
System.out.println("requestTransmission doing some long operation")
}
}
/* Need to send this event back to the activity/fragment */
private fun onTransmissionChanged(): Completable {
return Completable.fromCallable {
System.out.println("onTransmissionChanged send event to activity")
eventBus.post(TransmissionChanged())
}
}
}
Activity:
public class HomeActivity extends AppCompatActivity {
private Bus eventBus = new Bus();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
eventBus.register(this);
new Interactors(eventBus).transmitMessage()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe();
}
#Override
protected void onDestroy() {
eventBus.unregister(this);
super.onDestroy();
}
#Subscribe
public void onTransmissionChangedEvent(TransmissionChanged transmissionChanged) {
System.out.println("onTransmissionChangedEvent");
}
}
And the EventBus class:
class TransmissionChanged
This the output when I run the app:
insertTransmission doing some long operation
onTransmissionChanged
I am not sure if the eventBus.post(..) is blocking. Actually this should be done in the main thread as is posting back to the Activity to perform some update in the UI.
Do you really need to mix an EventBus and RxJava? For me this introduces extra complexity without a lot of benefit to it. Your use-case seems like a perfect example to use an Rx stream, doing some work on each emission (in your case updating the UI via onTransmissionChangedEvent()).
I'd change transmitMessage() method to something like this:
fun transmitMessage(): Observable<TransmissionChanged> {
return Observable.create(ObservableOnSubscribe<TransmissionChanged> { emitter ->
insertTransmission()
emitter.onNext(TransmissionChanged()) // perform this after the long running operation from insertTransmission() has finished
requestTransmission()
emitter.onComplete() // after the long running operation from requestTransmission() has finished
})
}
I guess you need some extra data to update your UI accordingly - this is encapsulated in TransmissionChanged class - include whatever you need there. One thing to be aware of - using Observable.create() is dangerous in RxJava 1. I don't remember what was the safe way of doing so and don't have a project with RxJava 1 to experiment with ... but there was a factory method in the Observable class that could do the job safely.
Using the above, your Activity code becomes cleaner as well. There's no need for Otto anymore, as all your operations are handled via the single Rx stream.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
new Interactors()
.transmitMessage()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(transmission -> onTransmissionChangedEvent(transmission),
throwable -> handleError(throwable),
() -> handleCompletion()
);
}
Not allowing the receiver to specify which thread it would like to receive events on is a short coming of Otto. It enforces that all calls need to be on the same thread (defaults to the main thread). It is up to the caller to get be on the correct thread. I much prefer EventBus by GreenRobot. You change which thread you want to receive on with an annotation. So, my first suggestion would be, if you are not too invested in Otto yet, is to consider using EventBus instead.
If you are not in a position to rework all your event bus code, you can post back to the main looper by allocating a Handler. It is quick and easy, but feels a little like stepping out of rx framework.
private fun onTransmissionChanged(): Completable {
return Completable.fromCallable {
System.out.println("onTransmissionChanged send event to activity")
Handler(Looper.getMainLooper()).post {
eventBus.post(TransmissionChanged())
}
}
}
If you are calling this a lot, you may want to cache the Handler and pass it into your Interactors constructor.
If you want to stick with RxJava schedulers, you can pass a Scheduler into your constructor to indicate where you want to do your background work instead of using subscribeOn. In transmitMessage, use it schedule the background ops while forcing the eventBus.post to the main thread as follows --
class Interactors(private val eventBus: Bus, private val scheduler: Scheduler) {
fun transmitMessage(): Completable {
return insertTransmission()
.subscribeOn(scheduler)
.observeOn(AndroidSchedulers.mainThread())
.andThen(onTransmissionChanged()) /* Send event to the activity */
.observeOn(scheduler)
.andThen(requestTransmission())
}
// Rest of the class is unchanged
}
in this case, you will use it in HomeActivity as follows --
new Interactors(eventBus, Schedulers.io()).transmitMessage()
.observeOn(AndroidSchedulers.mainThread())
.subscribe();
It is possible that your activity/fragment is not started/attached while posting the event so they haven't registered to the eventBus yet. By that the event was post, but there are no subscribers (or maybe there are other subscribers somewhere else).
Maybe you should use Sticky Events to make that event "awake" so your activity/fragment will still be able to handle it.
For using EventBus events as RxJava code, I do something as follows:
public class EventBusRx {
private static EventBusRx ourInstance = new EventBusRx();
public static EventBusRx getInstance() {
return ourInstance;
}
private EventBusRx() {}
public final Subject<Integer> eventName = PublishSubject.create();`
}`
And then listening to such event:
EventBusRx.getInstance().eventName
.subscribeOn(AndroidSchedulers.mainThread())
.doOnNext(o -> someAction())
.subscribe();
And for posting an event:
public void postSomeEvent(int eventValue) {
EventBusRx.getInstance().eventName.onNext(eventValue);
}
Also read about RxJava's Replay, which might be helpful for you.
Your Activity/Fragment should have this updated code:
#Override
public void onResume() {
super.onResume();
if (!eventBus.isRegistered(this))
eventBus.register(this);
}
#Override
public void onDestroy() {
super.onDestroy();
if (mEventBus.isRegistered(this))
mEventBus.unregister(this);
}
#Subscribe(threadMode = ThreadMode.MAIN)
public void onTransmissionChangedEvent(TransmissionChanged transmissionChanged) {
System.out.println("onTransmissionChangedEvent");
}
Now your code for Interactors should be like this
new Interactors(eventBus).transmitMessage()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Object o) {
onTransmissionChanged();
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
Use on next on next method to call onTransmissionChanged().

RxJava2 - Chaining observables that emit different types

I'm learning RxJava2 and I need to chain three observables:
The first one performs operations on the data:
Completable performOperations(Data data); // performs expensive operations.
The second one uploads data to a server1 and emits percentage progress.
Observable<Integer> uploadToServer1(Data data); // while it performs the upload, it calls several times onNext(progress) and finally calls onComplete().
The third one just informs to a server2 that the upload was done.
Completable informUploadedToServer2(Data data); // just calls a REST API.
I would like to show the progress in my Activity of the second observable and finally show success when the third one finishes successfully. If any of the three observables throws an exception I should show the error in the Activity as well.
I've tried to use concat to chain but it won't compile because uploadToServer1 emits the Integer type and the rest doesn't.
public void upload(Data data, MyCallback callback) {
Observable.concat(performOperations(data).toObservable(), uploadToServer1(data), informUploadedToServer2(data))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableObserver<Integer>() {
#Override
public void onNext(Integer integer) {
callback.onProgressChanged(integer);
}
#Override
public void onError(Throwable e) {
callback.onError();
}
#Override
public void onComplete() {
callback.onSuccess();
}
});
}
I've seen that if I change to
Observable.concat(performOperations(data).<Integer>toObservable(), uploadToServer1(data), informUploadedToServer2(data).<Integer>toObservable())
it will work, however, is this the recommended approach?
What is more, what if the first observable emits non-Integers?, for example, a DataDiff object which would describe the modification after a certain operation was performed:
Observable<DataDiff> performOperations(Data data);
How should I subscribe so that I can listen for onNext(Integer) and also onNext(DataDiff) so that the Activity can update the view accordingly?
Thanks.
I would do that in a different way, a more "streamy" approach.
First performOperations(), then use andThen operator to concatenate with the Observable<Integer>, and then you can use concatWith so that after that all the elements from the Observable<Integer> are emitted informUploadedToServer2 is executed. You can then handle the Integer emitted in the subscription consumer, if you observeOn(AndroidSchedulers.mainThread) you can than safely notify your Activity there
performOperations(data)
.andThen(uploadToServer1(data))
.concatWith(informUploadedToServer2(data))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Integer>() {
#Override
public void accept(Integer integer) throws Exception {
// notify your Activity here
}
});
In case you needed to intercept the completion of one of the streams, you could use doOnComplete, for instance
performOperations(data)
.doOnComplete(new Action() {
#Override
public void run() throws Exception {
// after performOperations has completed but before
// uploadToServer1 has started
}
})
.andThen(uploadToServer1(data))
// ...
In case performOperations() returned an Observable<DataDiff>, you could use doOnNext to intercept all the events, and then use ignoreElements operator to convert it to a Completable and then use andThen as before
performOperations()
.doOnNext(new Consumer<DataDiff>() {
#Override
public void accept(DataDiff dataDiff) throws Exception {
// handle DataDiff here
}
})
.ignoreElements()
.andThen(uploadToServer1())
// ...

Stoppable background timer/observable with RXAndroid

I am trying to create a repeating, background timer with RXAndroid. I have written code that executes at a specified interval in the background, but I cannot find a way to stop it.
Observer<Long> observer = new Observer<Long>() {
#Override
public void onSubscribe(Disposable d) {}
#Override
public void onNext(Long aLong) {
Log.d(LOGTAG, "Interval:" +String.valueOf(aLong));
}
#Override
public void onError(Throwable e) {}
#Override
public void onComplete() {}
};
Observable observable = Observable.interval(1, 1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io());
observable.subscribe(observer);
I would like to know please:
Is this the correct approach for creating a "timer" in RXAndroid to execute code periodically in the background?
How do I stop it?
Is this the correct approach for creating a "timer" in RXAndroid to execute code periodically in the background?
Yes,
How do I stop it?
To cancel the observer in RxJava you have to use the reference of Disposable.
Which you can find in the onSubscribe(Disposable d).
onSubscribe() will call whenever you subscribe to observable. in your case it is observable.subscribe(observer).
In observer you have method public void onSubscribe(Disposable d) {} which will provide reference of Disposable.
Declare global instance of Disposable, and whenever you want to cancel call Disposable::dispose().

When to unsubscribe a subscription

I have a question regarding how to unsubscribe an observable. I have two codes and I'm not really sure about which one is better.
Example 1 -> Unsubscribe the subscriber once the stream has finished:
Subscriber<String> subscriber = new Subscriber<String>() {
#Override
public void onCompleted() {
progressdialog.dissmiss();
unsubscribe();
}
#Override
public void onError(Throwable e) {
progressdialog.dissmiss();
}
#Override
public void onNext(String s) {
// do something with data
}
}
Example 2 -> Unsubscribe the subscription once the activity is destroyed:
private void test(){
Subscriber<String> subscriber = new Subscriber<String>() {
#Override
public void onCompleted() {
progressdialog.dissmiss();
}
#Override
public void onError(Throwable e) {
progressdialog.dissmiss();
}
#Override
public void onNext(String s) {
// do something with data
}
};
subscription = BackendRequest.login(loginRequest)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
compositeSubscription.add(subscription);
}
#Override
protected void onDestroy() {
super.onDestroy();
this.subscription.unsubscribe();
}
I have to mention that my observables only will emit once, the activity should not wait for more calls from the Observable.
Which one is better?
Thanks in advance
From the two options the second one is better.
In your first example you're unsubscribing in the onComplete() method which is not needed. If you reach the onComplete() of a Subscription you don't have the responsibility of unsubscribing from it anymore.
Your second example is the correct one. The idea behind the CompositeSubscription is that you can add multiple Subscriptions to it and then clean up (unsubscribe) at once. In other words this just saves you from the need of keeping a list of Subscriptions that you need to unsubscribe from.
One tricky part using CompositeSubscription is that if you once unsubscribe it, you can NOT use it again. You can check the documentation for the compositeSubscription.add() method for details why. In short - it will directly unsubscribe the Subscription you're trying to add. That's been a deliberate decision (you can read more about it HERE).
Coming back to your example, calling unsubscribe() in onDestroy() of the Activity is fine and will save you from memory leaks. Regarding your comment that problems occur when you call your test() method multiple times - I'd say your problem is somewhere else. Maybe your use-case shouldn't allow to call it multiple times, maybe you should cleanup old data before using the newly received one, etc. Perhaps if you have explained in details what kind of problems you face we could help more. But as far as the CompositeSubscription is concerned - you're using it and unsubscribing from it correctly!
There is no need to unsubscribe in onCompleted. Take a look at The Observable Contract
When an Observable issues an OnError or OnComplete notification to its
observers, this ends the subscription. Observers do not need to issue
an Unsubscribe notification to end subscriptions that are ended by the
Observable in this way.
On the other hand, you definitely should unsubscribe in onDestroy in order to prevent memory leaks.
I think that depends on your needs. If the activity won't wait for any other calls, I suppose you could unsubscribe inside onCompleted().
I always unsubscribe in onDestroy()
#Override
protected void onDestroy() {
super.onDestroy();
if (subscription != null) {
subscription.unsubscribe();
}
}
EDIT: take a look at http://reactivex.io/RxJava/javadoc/rx/subscriptions/CompositeSubscription.html
private CompositeSubscription mCompositeSubscription = new CompositeSubscription();
private void doSomething() {
mCompositeSubscription.add(
AndroidObservable.bindActivity(this, Observable.just("Hello, World!"))
.subscribe(s -> System.out.println(s)));
}
#Override
protected void onDestroy() {
super.onDestroy();
mCompositeSubscription.unsubscribe();
}

Categories

Resources