How to debounce a retrofit reactive request in java? - java

I'm working on an android project that makes requests through retrofit using Rx-Java observable and subscribe.
However, in some interactions this request can be called multiple times and I would like to only execute the last one in a predefined window of time (debounce).
I tried to apply the debounce operator directly to the observable, but it will not work because the code below is executed every time some interaction occurs:
mApi.getOnlineUsers()
.debounce(1, TimeUnit.SECONDS)
.subscribe(...)
I guess it should be created only one observable and every interaction it should "append" the execution to the same observable. But I am kind of new on Rx Java and don't know exactly what to do.
Thanks!

Suppose you want to start an execution according to some trigger event.
Observable<Event> trigger = ... // e.g. button clicks
You can transform the trigger events to calls to your API like this:
trigger
.debounce(1, TimeUnit.SECONDS)
.flatMap(event -> mApi.getOnlineUsers())
.subscribe(users -> showThemSomewhere(users));
Also, notice that the debounce operator will take the last occurrence within the time frame, but throttlefirst will take the first. You may want to use one or the other depending on your use case.

Related

Where is the Immediate Scheduler in rxJava3?

In rxJava 1 there was Scheduler.immediate() which let you schedule work on the current thread. In rxJava 3 I can no longer find this scheduler.
Does anyone know what the replacement for Scheduler.immediate() is in rxJava 3?
My use case:
I have a client-side API which I use to subscribe to an infinite stream of events (e.g. a news feed) from a remote server. The API notifies me of events via a callback which I register:
Observable.create(emitter -> apiClient.registerCallback(event -> emitter.onNext(event)))
.observeOn(Schedulers.immediate()) // I'd like downstream operators to run on current thread
.map(myFunc);
However, the API calls my callback from a different thread. I wish to run downstream computations like myFunc on the current thread (the one that created the Observable) so as not to block the API's thread.
AFAIK, in RxJava 3 you can employ ImmediateThinScheduler to obtain the same effect.
Although it's kept in the internal package, you can use it.
The API is so simple you can actually create one yourself if you don't want to depend on their internal package.

How can I explicitly signal completion of a Flowable in RxJava?

I'm trying to create a Flowable which is wrapping an Iterable. I push elements to my Iterable periodically but it seems that the completion event is implicit. I don't know how to signal that processing is complete. For example in my code:
// note that this code is written in Kotlin
val iterable = LinkedBlockingQueue<Int>()
iterable.addAll(listOf(1, 2, 3))
val flowable = Flowable.fromIterable(iterable)
.subscribeOn(Schedulers.computation())
.observeOn(Schedulers.computation())
flowable.subscribe(::println, {it.printStackTrace()}, {println("completed")})
iterable.add(4)
Thread.sleep(1000)
iterable.add(5)
Thread.sleep(1000)
This prints:
1
2
3
4
completed
I checked the source of the Flowable interface but it seems that I can't signal that a Flowable is complete explicitly. How can I do so? In my program I publish events which have some delay between them and I would like to be explicit when to complete the event flow.
Clarification:
I have a long running process which emits events. I gather them in a queue and I expose a method which returns a Flowable which wraps around my queue. The problem is that there might be already elements in the queue when I create the Flowable. I will process the events only once and I know when the flow of events stops so I know when I need to complete the Flowable.
Using .fromIterable is the wrong way to create a Flowable for your use case.
Im not actually clear on what that use case is, but you probably want to use Flowable.create() or a PublishSubject
val flowable = Flowable.create<Int>( {
it.onNext(1)
it.onNext(2)
it.onComplete()
}, BackpressureStrategy.MISSING)
val publishSubject = PublishSubject.create<Int>()
val flowableFromSubject = publishSubject.toFlowable(BackpressureStrategy.MISSING)
//This data will be dropepd unless something is subscribed to the flowable.
publishSubject.onNext(1)
publishSubject.onNext(2)
publishSubject.onComplete()
Of course how you deal with back-pressure will depend on the nature of the source of data.
Like suggested by akarnokd, ReplayProcessor do exactly what you want. Replace iterable.add(item) with processor.onNext(item), and call processor.onComplete() when you are done.

What will happen after timeout when using Observable.timeout?

I have an Observable that go to database and query for some information. I don't want my observable executes longer than 5 seconds, thus I use:
myObservable.timeout(5,second);
Then I want to handle the error notification also, thus I use:
myObservable.timeout(5,second).onError(return empty result);
Then I wonder for what will happen to the code in myObservable that is used to do database query. Will it also be terminated, or it will continue to run ? (which happens to Java native Future.get(timeLimit))
Let's take an example :
Observable.interval(1, TimeUnit.SECONDS)
.timeout(10, TimeUnit.MICROSECONDS)
.onErrorReturn(e -> -1L)
.subscribe(System.out::println,
Throwable::printStackTrace,
() -> System.err.println("completed"));
the timeout operator will emit an error. But precedent operators won't be notifier of this error.
The operator onErrorReturn will transform your error to an event and then will complete your stream (and mark it as finished) and then your source observable will be unsubscribe.
This unsubscription part will run some code that, depending of how your source observable is written, that may stop your request, or just do nothing, or free some resources.
In your case, it may call the cancel method on your Future (according to the Subscriptions class)

Get data from 3 different websites synchronously using RxJava

I'm very new to RxJava, and I want to get content from 3 different webpages synchronously. How do I go about doing this?
You can use concat to make the calls happen in sequence:
Observable call1 = ...
Observable call2 = ...
Observable call3 = ...
Observable.concat(call1, call2, call3).subscribe(...);
You can use toBlocking to make the reception synchronous:
Observable.concat(call1, call2, call3).toBlocking().forEach(...);
I believe you want to achieve parallel execution of your observables, you can do this by using combineLastest operator. In short, you should create 3 observables and merge their results via combineLastest. In this case subscribe will be triggered once each observable emits something.
For further information, please see:
http://reactivex.io/documentation/operators/combinelatest.htm

RxJava: restart from the beginning on each subscription

Imagine I have some time consuming task which I want to run only occasionally.
I want to wrap it into an observable and pass it to some component.
That component will subscribe to this observable whenever it wants to retrieve the data, and unsubscribe after it receives it.
I.e. I want an observable which upon subscription would invoke some expensive API call, and this API call can return a different data each time it is called - and then this observable would shut down until next subscription is made.
Is this possible to achieve?
I have seen 'replay()' and 'cache()' operators, but they won't work because from what I understood, they will cache once and then replay cached values which fails my case of changing data.
Also there is 'observable.publish()' but it seems that this will make a hot observable which will stay connected to the source observable all the time...
As I understand your question, you need a cold observable.
Observable<Integer> obs = Observable.from(1, 2, 3, 4);
obs.subscribe(); // will iter over values
obs.subscribe(); // will iter AGAIN over values
So, if your observable is your api call, and it's a cold observable, just subscribe twice on it to perform two api calls.

Categories

Resources