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.
Related
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.
I have a List which contains a record of various CallLog objects. Every CallLog is different, and when I pass this to my ListView, each log is correctly displayed on my screen. What I want to do, however, is remove logs which have the same RemoteAddress attribute (i.e. a person who called me or has received a call by me should only appear once in my ListView). This is because I will display all log details for that remote contact directly below it.
How can I create a method (or class), which could filter out my List to only keep unique Remote Addresses? Below is how I retrieve this log list from the core. It has the form of a CallLog[]:
// Filter this
List<CallLog> mLogs = Arrays.asList(LinphoneManager.getCore().getCallLogs());
List<CallLog> mLogs = Stream.<CallLog>of(LinphoneManager.getCore().getCallLogs())
.collect(ArrayList::new,
(a, l) -> { if (!a.stream().anyMatch(o -> ((CallLog) o).remoteaddress.equals(l.remoteaddress))) a.add(l); },
(a, b) -> { a.addAll(b); })
Have you tried something like this before? You can use set method rather than add.
I am following this example here from the doc
Here is part of the finite state machine I'm working with
startWith(ACCEPTED, new myData());
when(ACCEPTED, matchEvent(someMesage.class, MyData.class,
(someMessage, myData) -> goTo(EVALUATING).replying(EVALUATING)));
onTransition(matchState(ACCEPTED,EVALUATING, () -> {
// Here I want to update the nextState data and pass it to another actor
// But the nextState data is always the unititalized object which is new Mydata() when the FSM initializes
}));
whenUnhandled(matchAnyEvent(
(state, data) -> stay().replying("received unhandled request " + state.toString())));
initialize();
}
How do I correctly pass data between various states in the state machine?
How should the actor.tell call look like for the actor sending a message to this FSM actor
If I send the following message
MyFSM.tell(new someMessage(myData), getSelf());
It correctly matches the event and the actor changes the state to EVALUATING and sends back an EVALUATING message. BUt what I really want is, modify 'myData' based on this state change and on transition, send this modified data to another actor.
But when I send a message of type someMessage I have no way to send the existing instance of myData and it is always uninitialized as part of the initialization of the state machine.
In other words, I am trying to manage the state of myData with the finite state machine.
How can I achieve his making the best use of the framework?
A working example from the above information will be really useful!
You can use using to provide a new state, like so:
when(ACCEPTED, matchEvent(someMesage.class, MyData.class,
(someMessage, oldData) -> {
MyData newState = new MyData(); // or transform the old into a new one
return goTo(EVALUATING).using(newState).replying(EVALUATING);
}));
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 and app that connects to a socket connection and that connections sends me a lot of info.. lets say 300 orders per second (maybe more).. I have a class (it is like a listener, that reacts to some event and that event has the order) that receives that order.. creates an object and then adds it to an ObservableList (which is the source of a tableView).. that way my GUI shows that order. But here comes the problem, if that order already exists on the observableList.. i can't add it ..and i must update it (wich i do).. but some times.. with some orders this condition doesn't work and the order its added again.
Im gonna show you how it's work with some code.
public class ReceivedOrderListener
{
ev = Event; //Supose that this is the event with the order
if(!Repository.ordersIdMap.containsKey(ev.orderID))
{
Platform.runLater(new Runnable()
{
#Override public void run()
{
Repository.ordersCollection.add(ev.orderVo);
}
}
});
Repository.ordersIdMap.put(ev.orderID, ev.orderVo);
}
Ok now.. this is a resume of my code. The ev is my event with all the info of the order, the orderID is the key that i use to see if the order already exists or not (and yeah is unique). The "Repository" is a singleton class, the "ordersCollection" is a ObservableList, the "ordersIdMap" is a HashMap
If ReceivedOrderListener is executed by multiple threads, then it looks like "check-then-act" race condition.
-> ORDER1 comes to the listener
T1 checks ordersIdMap.containsKey(ORDER1) it returs false
T1 proceeds to do Platform.runLater to add the order
-> ORDER1 comes to the listener again
-> T2 checks ordersIdMap.containsKey(ORDER1) it returs false again
now T1 proceeds to do ordersIdMap.put(ORDER1)
-> T2 proceeds to do Platform.runLater to add the order again