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();
}
Related
I am new in retrofit/rxjava-android
Someone told me that, it is best practice if I will cancel the request if the call is not yet finished and the user leaves the activity page.
I am having problem where/how to cancel it.
Here's my code, it is working properly.
Observable<List<MyObject>> call;
public void getStaticMessages() {
call = restInterface.loginURL();
call.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<List<MyObject>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
Log.d("LOGGER", "error");
}
#Override
public void onNext(List<MyObject> myObjects) {
Log.d("LOGGER", "succcess");
}
});
}
One of the best practice is to create subscription/disposable when onStart() method of activity/fragment is called and unsubscribe /dispose when onStop called.
You can create one disposable Disposable disposable = call.subscribeOn and dispose it via disposable.dispose() or use CompositeDisposable.
I used the same approach with CompositeDisposable in one of my previous pet projects - link
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();
}
I've done an Rxjava wrrapper for firebase signInWithCustomToken() method, here is the code:
public Observable<AuthResult> signInWithCustomToken(String token) {
return Observable.create(new ObservableOnSubscribe<AuthResult>() {
#Override public void subscribe(ObservableEmitter<AuthResult> emitter) throws Exception {
firebaseAuth.signInWithCustomToken(token)
.addOnSuccessListener(new OnSuccessListener<AuthResult>() {
#Override public void onSuccess(AuthResult result) {
emitter.onNext(result);
}
})
.addOnFailureListener(new OnFailureListener() {
#Override public void onFailure(#NonNull Exception e) {
emitter.onError(e);
}
})
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override public void onComplete(#NonNull Task<AuthResult> task) {
emitter.onComplete();
}
});
}
});
}
so I was wondering what is the lifecycle of the three listeners (OnSuccessListener - OnFailureListener() - OnCompleteListener) inside the Rx callback, Do they have the same lifecycle of the return Observable, in other words if I called observable.dispose(), will they be cleared from memory?
and I have another question sorry, is this the best way for modeling such a method in Rx way?
thank you in avance.
I'm answering my question, calling dispose() doesn't guarantee removing those listeners from memory. but there is a nice solution for this.
each time you create an Observable from listeners or callback make sure to setup a Cancellable and clear things there.
emitter.setCancellable(new Cancellable() {
#Override
public void cancel() throws Exception {
//clean memory
}
});
however the case with code mention in question, that firebase doesn't provide a method to clear those listeners in signwithCustomToken(). but other like DatabaseReference has removeListenr() method to clear things when canceling.
emitter.setCancellable(new Cancellable() {
#Override
public void cancel() throws Exception {
databaseReference.removeEventListener(valueEventListener);
}
});
Do they have the same lifecycle of the return Observable, in other words if I called observable.dispose(), will they be cleared from memory?
No, you need to specify the disposable logic yourself, and there remove your listeners from firebaseAuth, you can do it using either Emitter.setDisposable() or Emitter.setCancellable(), if you will not supply it, then the Observable will merely untie the connection between the Subscriber and the Observable and will stop emit events, but the listeners will stay registered to firebaseAuth and memory leak might happen.
and I have another question sorry, is this the best way for modeling such a method in Rx way?
using RxJava2 create methods is valid method for wrapping async callbacks methods. However, with RxJava2 the default way with lowest overhead is to extend Observable and use Observer methods to notify events/ register dispose callback. you can read more here.
This is my first time developing in reactive paradigm world, and i started using rxjava2/rxandroid2, as based on videos I've watched and articles I've read, it seems like its better to start with 2 as 1 has so many changes that differs the library in a big scale, but now I'm having some trouble looking for something that acts like the
unsubscribe()
method of the former rxjava/rxandroid library
my goal is just quite simple
perform an API call(network operation)
listen and react on what the observable will emit (happy path)
do not listen or react when app goes to PAUSE state
or, unsubscribe on observable as soon as android goes to the pause life-cycle
, based on the resources around there is
dispose()
method of rx2, what I understand with this is that it disposes any current resources(in my case, base on what i understand, invoking this will make the observable detach itself to any observer).
but that doesn't seem to be what I'm expecting, please have a look at the ff codes:
public class MainActivity extends AppCompatActivity {
final Disposable disposable = new Disposable() {
#Override
public void dispose() {
Log.e("Disposed", "_ dispose called.");
}
#Override
public boolean isDisposed() {
return true;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Observer<Object> observer = new Observer<Object>() {
#Override
public void onSubscribe(Disposable d) {
Log.e("OnSubscribe", "On Subscribed Called");
}
#Override
public void onNext(Object value) {
Log.e("onNext", "Actual Value (On Next Called).");
}
#Override
public void onError(Throwable e) {
e.printStackTrace();
}
#Override
public void onComplete() {
Log.e("OnComplete", "On Complete Called.");
}
};
EventsApiService.getInstance().testApi().testCall()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnDispose(new Action() {
#Override
public void run() throws Exception {
Log.e("Disposed?", "__ Dispose");
}
})
.subscribe(observer);
observer.onSubscribe(disposable);
}
#Override
public void onPause() {
super.onPause();
disposable.dispose();
}
}
I'm having this output:
03-23 09:08:05.979 3938-3938/edu.rx.study E/Disposed: _ dispose called.
03-23 09:08:13.544 3938-3938/edu.rx.study E/onNext: Actual Value (On Next Called).
03-23 09:08:13.544 3938-3938/edu.rx.study E/OnComplete: On Complete Called.
I was expecting that onNext won't be called anymore or maybe both onNext and onComplete, but that doesn't seem to be working, am i missing something here? or theres something i totally don't understand, my thinking with my code is,
"what if onNext is performing something towards a widget(UI)(Observer) and the app goes on pause state?", I don't want that UI(Observer) to react on that particular UI anymore.
Many people are right, and I admit, switching to reactive programming is quite hard especially rxjava2/rxandroid2 has a very steep learning curve.
Any help will be greatly appreciated.
You're handling incorrectly the Observer and the Disposable, the Disposable object should be handing to you by the Observable, you can't just create it by yourself, and call explicitly Observer.onSubscribe() with it, as it's not connected to the Observable and does not terminates it.
(you can also notice that Observer.onSubscribe is called twice, one by the Observable and one by you)
What you should do, is simply use the onSubscribe(Disposable d) method at your Observer to save the Disposable, which will be called automatically by the Observable and will hand you the correct Disposable object, that you can successfully terminate the network operation with it.
Another option is, to not use at all the subscribe(Observer o) method, but other overloads that takes your onNext/onError/onCompleted as parameters, and returns Disposable object, which you can dispose (unsusbcribe) with it, for terminating the network call.
I have an Observable and subscribe to it. I need to not miss any emitted result, so I use onBackpressureBuffer like following:
Observable<Data> observable = observable.onBackpressureBuffer();
if (BuildConfig.DEBUG)
{
observable
.subscribeOn(HandlerScheduler.from(dataManager.getBackgroundHandler()))
.observeOn(HandlerScheduler.from(dataManager.getBackgroundHandler()))
.subscribe(new MeasuringSubscriber(...));
}
// Here is the real observer that I need in my app
observable
.subscribeOn(HandlerScheduler.from(dataManager.getBackgroundHandler()))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Data>()
{
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(Data data) {
}
});
The MeasuringSubscriber is a custom subscriber that just logs how long a task needs, that's all.
Problem
If I add the MeasuringSubscriber, the subscribers do not work anymore and never emit a result. Why? And how can I make that working?
EDIT - NEW PROBLEM
Currently it's working, but the MeasuringSubscriber is somehow blocking, meaning, first all items are emitted one by one to the MeasuringSubscriber and only afterwards all items are emitted one by one to the main subscriber... Any ideas what could cause that?
I have a solution for that - I can extend my main observalbe from the MeasuringObservable - but I rather would like to know why this happens and how to avoid this...
I tried using publish + connect, but still it does emit all items to the first subscriber before emitting them to the second one...