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().
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();
}
is there a way to change the Observable.interval period at runtime?
and is there a way to stop and resume the Observable.interval ticks?
and is there a way to reset the interval period?
actually I'm using the following code to do an action for ever in a period time, but I have no control on it during the run time, I have to stop, resume, rest, and change the period at runtime.
Observable.interval(8, TimeUnit.SECONDS).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Long>() {
#Override
public void onSubscribe(Disposable d) {
Log.i("TAG", "onSubscribe");
}
#Override
public void onNext(Long aLong) {
myMethod();
}
#Override
public void onError(Throwable e) {
Log.i("TAG", "onError");
}
#Override
public void onComplete() {
Log.i("TAG", "onComplete");
}
});
I have tried to google it to find a solution, but unfortunately I did not find any one, and I need a help or a resource if there is any.
As #DDH indicated, perhaps the simplest way is to cancel an ongoing interval and start a new flow completely.
However, if you have to maintain the chain below the interval for some reason, you can switch to a new interval via the switchMap operator, triggered by a PublishSubject for example:
PublishSubject<Long> newInterval = PublishSubject.create();
newInterval.switchMap(currentPeriod ->
Observable.interval(currentPeriod, TimeUnit.MILLISECONDS)
)
.doOnNext(v -> { /* background work */ })
.observeOn(AndroidSchedulers.mainThread())
.subscribe(/* ... */);
newInterval.onNext(1000L);
// sometime later
newInterval.onNext(200L);
Here it is my solution to handle the issue
private PublishSubject<Long> newInterval;
// reactive programming using RXJava2
private void prepareObserver() {
newInterval = PublishSubject.create();
newInterval.switchMap(currentPeriod ->
Observable.interval(currentPeriod, TimeUnit.MILLISECONDS).subscribeOn(Schedulers.single())
)
.doOnNext(v -> runOnUiThread(this::pagerForeword))
.subscribe();
newInterval.onNext(period);
}
and to reset the interval period I call
newInterval.onNext(period);
and you can find the full solution over the following resource tutorial here
I hope this be useful!
I'm not 100% sure what did you mean by " I have to stop, resume, rest, and change the period at runtime."
But you can dispose subscription and reinit observable with new period on runtime:
Disposable d = Observable.interval(1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.single())
.subscribe(new Consumer<Long>() {
#Override
public void accept(Long aLong) throws Exception {
}
});
d.dispose();
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 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();
}