The "neverending" Observable emits a parameter item as soon as the user changes something on the ui.
depending on this item I need to do a request. as soon as the parameter item changes the request should be stopped and a new one started.
parameterObservable
.switchMap(this::search) // to stop an restart the request with new params
.toList()
.subscribe(resultList -> {/* do something*/});
The Problem here is that, the toList Operator waits for the parameterObservable to complete. Which will not happen.
To make the toList work I could do something like this:
parameterObservable
.subscribe(params -> search(params).toList()
.subscribe(/* do something */)
);
But then the switchMap is missing.
How can I achieve this?
How about this:
parameterObservable
.switchMap(params -> search(params).toList())
.subscribe(resultList -> {/* do something*/});
Related
I'm using RxHttpClient to make requests and return Single using .firstOrError(). I then subscribe to it to get the result. In order to dispose of that subscription, I used a CompositeDisposable like in the example below.
Is there some other way to do this that doesn't require so much boilerplate? Do I need to do this at all in the current situation?
This code is in an API that needs to make a request to another API to validate some data.
single = httpClient.retrieve(HttpRequest.POST("/endpoint", request), ResultDto.class)
.firstOrError()
.subscribeOn(Schedulers.io())
CompositeDisposable cd = new CompositeDisposable();
Disposable d = single.subscribe(result -> {
// ...
cd.dispose();
}, error -> {
cd.dispose();
});
cd.add(d);
Pretty much all of this is necessary, assuming you don't actually create CompositeDisposable like that and then throw it away.
You can save cd.add(d); and perhaps Disposable d= with RxJava 3 if you supply cd as the third parameter to subscribe.
When I try to read the reactions added to a message sent I'm always getting an empty list.
MessageBuilder mb = new MessageBuilder();
channel.sendMessage(mb.build()).queue((t);
After adding reactions to it, I execute this code:
System.out.println(t.getReactions().size());
for (MessageReaction r : t.getReactions()) {
System.out.println(r.getReactionEmote().getName());
}
(this is yet to be implemented, I'm just trying to get to understand how I can use it)
I am expecting the output to be the amount of reactions I added, yet System.out.println(t.getReactions().size()); will always print 0 regardless of the amount of reactions added to the message sent.
Furthermore, when iterating of the list containing reactions, it always won't print anything to the console, since the list seems to be empty.
Is there something I need to add that I can use .getReactions()?
What I also tried is using an eventWaiter:
eventWaiter.waitForEvent(GuildMessageReactionAddEvent.class, (event) -> {
return "🎵".equals(event.getReactionEmote().getName()) && !event.getUser().isBot()
&& event.getMessageIdLong() == messageId;
}, (event) -> {
System.out.println("Reacting to reaction");
}, (long) 30, TimeUnit.SECONDS, () -> {
System.out.println("Timeout. No event was registered.");
});
This always outputs the timeout warning, regardless of reactions added.
This is not how JDA works.
The reactions do not get magically updated, you can get the reactions by fetching the message or by listening for the reaction add event.
To use the event waiter properly you must make sure that the same instance is also registered on JDA by using JDABuilder#addEventListeners.
So either listen for the event manually or make sure that you only use once instance of the EventWaiter class in your code that is also registered on the JDA builder.
im trying to have a pattern, where my observable which produces some object, is transformed into domain events like Started, Success, Error emited around the observable producing, if that makes sense
public Observable<BookRenderingEvent> extractAndRenderObservable(String epubPath) {
return extractObservable(epubPath)
.flatMapObservable(extractedEpub -> renderObservable(extractedEpub)
.<BookRenderingEvent>map(renderedEpub -> new BookRenderingEvent.Success(renderedEpub))
.onErrorReturn(t -> new BookRenderingEvent.Error())
.startWith(new BookRenderingEvent.Started()));
}
private Observable<RenderedEpub> renderObservable(ExtractedEpub extractedEpub) {
return Observable.combineLatest(readerConfigObservable(), pagerDimensionsObservable(), ..)
.switchMapSingle(foo -> doRenderObservable()) <--- heavy work
.map(bar -> new RenderedEpub(bar))
}
renderObservable contains a heavy action so I want to emit these state events, so UI can react accordingly (with success containing the extractedEpub object as you can see in the map)
What my problem is that, renderObservable contains combineLatest(), so it "stays open" and emit mutiple times in time, whenever its obervables emit.
So the flow of events is Started, Success, Succes ... Success.
I want it to be Started, Success, Started, Success .. etc. i.e prepend Started event whever combineLatest emits, but my rx knowledge is insufficient.
Thanks
You could insert the following into the observable chain at the right place:
.flatMap( event -> Observable.just( new BookRenderingEvent.Started(), event )
This will emit the Started event before every event that it receives.
Of course, you could add in some logic so that you don't issue Started if the event is Started, etc.
Ok Ive managed to figure it out. The key info I was missing is that right side of flatmap gets subscribed when left side emits. Therefore the startWith had to be moved to the right side of flatmap observable, that gets subscribed to when ever combineLatest emits
public Observable<BookRenderingEvent> extractAndRenderObservable(String epubPath) {
return extractObservable(epubPath)
.flatMap(extractedEpub -> Observable.combineLatest(readerConfigObservable(), pagerDimensionsObservable(), ..)
.switchMap(foo -> renderObservable(extractedEpub)
.<BookRenderingEvent>map(renderedEpub -> new BookRenderingEvent.Success(renderedEpub))
.onErrorReturn(t -> new BookRenderingEvent.Error())
.startWith(new BookRenderingEvent.Started()));
}
I have Rx Stream where I'm using a grouped observable to have multiple observable according to a discriminant value. The thing is that I want to keep in memory the last subscription of each group observable in order to delete the stream when a new one is created (unsubscribe)
I'm using a simple Hashmap to store value according to a key which is an observable it self but it doesn't to worth it.
Here is where I am so far:
stream
.groupBy(ts -> ts.getLogin())
.map(receptor -> receptor.asObservable())
.forEach(consumer -> {
controlConsumer(consumer);
});
public void controlConsumer(Observable<Number> pConsumer) {
Subscription mySubscription = pConsumer
.buffer(2,1)
.subscribe();
// Remove the current consumer last subscription if existing
if(consumersLastSubcriptions.containsKey(pConsumer)) {
LOG.info("removing last subscription");
Subscription lLastSubscription = consumersLastSubcriptions.get(pConsumer);
lLastSubscription.unsubscribe();
}
// store the new consumer subscription
consumersLastSubcriptions.put(pConsumer, lSubscription);
}
UPDATE
Actually i might have different items defined by the login of the user emitting them. What i want is to store the last subscription of each user in order to remove it when i need to recreate a new one when needed. My purpose is to shutdown every stream no more used and don't let them open for nothing.
I have a label which displays error messages. If you double click on it you get a big dialog showing the whole stack trace. I have two observables: One for the errors and one for the click events:
final ConnectableObservable<Notification> errorNotifications = pm
.getNotificationObservable()
.filter(notification -> notification.getType().isError() && !notification.getLongMessage().isEmpty())
.replay(1);
errorNotifications.connect();
SwingObservable.fromMouseEvents(dialog.getMessagePanel().getMessageLabel())
.map(MouseEvent::getClickCount)
.filter(number -> number >= 2)
.subscribe(integer -> errorNotifications
.take(1)
.subscribe(notification -> ErrorDialog.showError(dialog.getFrame(), "Error", notification.getLongMessage())));
I filter the notification observable to only show erros and replay the last error if I subscribe from it from inside my click observable.
Now my question is, are there any operators in RxJava by which I can do this more... neatly? I tried to use combineLatest() but this had the effect, that every time an error ocured the dialog would open.
In a more abstract way: I have two observables, one is like the "master": If the master observable (click observable) emits an item, the other observable (my error notifications) should emit the latest item.
Using another Observable in a subscription is often a design flaw.
You may check the flatMap operator in this response. It will help you to emits error notification when you emit another event.
For example, if you want to use flatMap operator with your code, it can be updated like this :
final ConnectableObservable<Notification> errorNotifications =
pm.getNotificationObservable()
.filter(notification -> notification.getType().isError() && !notification.getLongMessage().isEmpty())
.replay(1);
errorNotifications.connect();
SwingObservable.fromMouseEvents(dialog.getMessagePanel().getMessageLabel())
.map(MouseEvent::getClickCount)
.filter(number -> number >= 2)
.flatMap(integer -> errorNotifications.take(1))
.subscribe(notification -> ErrorDialog.showError(dialog.getFrame(), "Error", notification.getLongMessage())));