I need to observe a list of objects and emit an event as soon as there is a new object in the list. Like a client - server application where the client adds content to the list and the server emits the newly added content to all the clients registered in the server.
So far, my observable only emits one item and nothing more after it. In other words, when a new object is added in to the list there is an event but when a second (or 3rd, 4th, 5th...) object is added there is no event.
I need it to keep emiting items as soon as there are new objects in the list.
This is my code, where MyList is let's say my own implementation of List (not relevant to my question). I want the emitted event to be the newly added object to MyList.
private void onClickMethod() {
MyList myList = populateMyList();
onNexAction = new Action1<MyList>() {
#Override
public void call(MyList myList) {
System.out.println("call()");
TheObject theObject = myList.getNext();
System.out.println("New Event: " + theObject.getData());
}
};
myObservable = Observable.create(new Observable.OnSubscribe<MyList>() {
#Override
public void call(Subscriber<? super MyList> t) {
t.onNext(myList);
}
});
myObservable.observeOn(Schedulers.newThread()).subscribeOn(Schedulers.io()).subscribe(onNexAction);
}
The code above will only emit the first added object. But if I place a while cycle inside call() it will be emitting all the events, like I want. But I feel like not the appropriate way to do what I want. I feel like I'm more like polling rather than async.
Here is the exact same code but with the while cycle:
private void onClickMethod() {
MyList myList = populateMyList();
onNexAction = new Action1<MyList>() {
#Override
public void call(MyList myList) {
System.out.println("call()");
while (myList.size() > 0) { // The while cycle
TheObject theObject = myList.getNext();
System.out.println("New Event: " + theObject.getData());
}
}
};
myObservable = Observable.create(new Observable.OnSubscribe<MyList>() {
#Override
public void call(Subscriber<? super MyList> t) {
t.onNext(myList);
}
});
myObservable.observeOn(Schedulers.newThread()).subscribeOn(Schedulers.io()).subscribe(onNexAction);
}
So, what am I doing wrong here? How can I keep my observable emitting a new event as soon as there is a new object in MyList?
EDIT:
As suggested by Tassos Bassoukos, I applied the distinct() operator like this:
myObservable.observeOn(Schedulers.newThread()).subscribeOn(Schedulers.io()).distinct().subscribe(onNexAction);
But it doesn't solve my problem. Only the first added object is emitted.
This is a typical case for PublishSubject:
class MyList<T> {
final PublishSubject<T> onAdded = PublishSubject.create();
void add(T value) {
// add internally
onAdded.onNext(value);
}
Observable<T> onAdded() {
return onAdded;
}
}
MyList<Integer> list = populate();
Subscription s = list.onAdded()
.subscribe(v -> System.out.println("Added: " + v));
list.add(1); // prints "Added: 1"
list.add(2); // prints "Added: 2"
list.add(3); // prints "Added: 3"
s.unsubscribe(); // not interested anymore
list.add(4); // doesn't print anything
list.add(5); // doesn't print anything
According to your code, when an user click (on something), the onClickMethod is called.
this method will create an object myList and you'll build an item that will emit this object. Then you'll consume this object.
In fact, you'll just emit your list once, that's why you're only notify once (on one click)
To achieve what you're looking for, a possible way is to emit each item of your list when you add one.
private void onClickMethod() {
MyList myList = populateMyList();
myObservable = Observable.create(subscriber -> {
int currentSize = myList.size();
while(myList.size() != currentSize) {
subscriber.onNext(myList.getNext());
currentSize = myList.size();
}
subscriber.onCompleted();
});
myObservable.observeOn(Schedulers.newThread())
.subscribeOn(Schedulers.io())
.subscribe(item -> System.out.println(item));
}
Please note that this code is NOT performant as it will loop over myList.size() and you may encounter issue if someone add/remove items during the loop code.
A better approach would be to be notified when a new item is added in myList, then emit this new item.
First, the reason you are not getting more than one value from your observable is that the method that you pass to Observable.create is only called once, and that occurs when it is first subscribed to. If you want to just hook up your list as an observable the easiest way is to make MyList class implement Iterable and you can directly use from instead
private void onClickMethod() {
MyList myList = populateMyList();
Observable.from(myList)
.observeOn(Schedulers.newThread())
.subscribe(item -> System.out.println(item));
}
Related
I have a MyObject() extends Thread which creates a new MyObject of itself in the run() method.
This object has a List<E> as a member, where I delete from under certain conditions.
I when creating the new Object I call start() afterwards to start it's run method. But as soon as I spawn the new Object, it throws an
Exception in thread "Thread-1" java.lang.UnsupportedOperationException
at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:73)
at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.remove(ImmutableCollections.java:80)
at mypackage.MyMainClass.MyObject.run(MyObject.java:87) <- here I remove from my List
Example:
public class MyObject extends Thread {
List<SomeType> list = new ArrayList<SomeType>();
SomeType st;
public MyObject(SomeType st) {
this.st = st;
// returns a List of SomeType
list = st.getList();
}
#Override
public void run() {
while(!done) {
SomeType toDelete;
if (condition) {
toDelete = st.getToDelete();
}
// Checks for null etc are done and not important
for (SomeType sometype : list) {
if (somecondition) {
// toDelete is always in that List
list.remove(toDelete)
}
}
if (lastcondition) {
MyObject newObject = new MyObject(this.st);
newObject.start();
}
}
}
}
Why do I get this error? Since the List is a member of each instance of the Object, why is it immutable for the new Threads, but not for my initial object?
Even when you fix UnsupportedOperationException your code that removes elements from list will throw ConcurrentModificationException because you are modifying list without using iterator while traversing list using iterator
for (SomeType sometype : list) { // this creates iterator behind the scene
if (somecondition) {
// toDelete is always in that List
list.remove(toDelete); // this modifies the list and makes iterator throw ConcurrentModificationException
}
}
Problem was pointed out by #Joachim Sauer:
SomeType.getList returns a List implementation that does not support structural modification (or maybe no modification at all). See this question for a similar problem (with add(), but the problem source and solution is very similar).
The used list got created with List.of()which is immutable.
I'm using RxJava, and I need to do 2 things:
Get the last element emitted from the Observable
Determine if onError was called, vs. onCompleted
I've looked at using last and lastOrDefault (which is actually the behavior I need), but I've not been able to work around onError hiding the last element. I would be OK with the Observable being used twice, once to get the last value and once to get the completion status, but so far I've only been able to accomplish this by creating my own Observer:
public class CacheLastObserver<T> implements Observer<T> {
private final AtomicReference<T> lastMessageReceived = new AtomicReference<>();
private final AtomicReference<Throwable> error = new AtomicReference<>();
#Override
public void onCompleted() {
// Do nothing
}
#Override
public void onError(Throwable e) {
error.set(e);
}
#Override
public void onNext(T message) {
lastMessageReceived.set(message);
}
public Optional<T> getLastMessageReceived() {
return Optional.ofNullable(lastMessageReceived.get());
}
public Optional<Throwable> getError() {
return Optional.ofNullable(error.get());
}
}
I've no problem with making my own Observer, but it feels like Rx should be better able to meet this use-case of "get the last element emitted before completion`". Any ideas on how to accomplish this?
Try this:
source.materialize().buffer(2).last()
In the error case the last emission will be a list of two items being the last value emitted wrapped as a Notification and the error notification. Without the error the second item will be the completion notification.
Note also that if no value is emitted then the result will be a list of one item being the terminal notification.
I solved with:
source.materialize().withPrevious().last()
where withPrevious is (Kotlin):
fun <T> Observable<T>.withPrevious(): Observable<Pair<T?, T>> =
this.scan(Pair<T?, T?>(null, null)) { previous, current -> Pair(previous.second, current) }
.skip(1)
.map { it as Pair<T?, T> }
Have you try onErrorResumeNext here you can see the rest or error handling operators https://github.com/ReactiveX/RxJava/wiki/Error-Handling-Operators
I used this approach to solve your problem.
public class ExampleUnitTest {
#Test
public void testSample() throws Exception {
Observable.just(1, 2, 3, 4, 5)
.map(number -> {
if (number == 4)
throw new NullPointerException();
else
return number;
})
.onErrorResumeNext(t -> Observable.empty())
.lastOrDefault(15)
.subscribe(lastEmittedNumber -> System.out.println("onNext: " + lastEmittedNumber));
}
}
It will emit onNext: 3
Hope that it helps.
I have a JavaFX service and I want to be notified via a callback when the Service updates a custom property. Normally the way this is done is that the service has some built in properties like "state", "workDone", "value" etc. The one most similar to the one I want to emulate is the "value" named property. The "value" property is defined as follows in the service class.
private final ObjectProperty<V> value = new SimpleObjectProperty<>(this, "value");
#Override public final V getValue() { checkThread(); return value.get(); }
#Override public final ReadOnlyObjectProperty<V> valueProperty() { checkThread(); return value; }
In my case I needed to listen to updates to a pair of message objects being updated by my JavaFX service thread, so I added a custom named property for each one as shown below.
// add 'heartbeat' bound property
private final ObjectProperty<CAServiceHeartbeatMessage> heartbeat =
new SimpleObjectProperty<>(this, "heartbeat", null);
public CAServiceHeartbeatMessage getHeartbeat() {
return heartbeat.get();
}
public void setHeartbeatMessage(CAServiceHeartbeatMessage aHeartbeat) {
heartbeat.set(aHeartbeat);
}
public ObjectProperty<CAServiceHeartbeatMessage> heartbeatProperty() {
return heartbeat;
}
// add 'memberSystemStatus' bound property
private final ObjectProperty<MemberSystemStatusMessage> memberSystemStatus =
new SimpleObjectProperty<>(this, "memberStatus", null);
public MemberSystemStatusMessage getMemberStatus() {
return memberSystemStatus.get();
}
public void setMemberSystemMessage(MemberSystemStatusMessage aMemberSystemStatus) {
memberSystemStatus.set(aMemberSystemStatus);
}
public ObjectProperty<MemberSystemStatusMessage> memberSystemStatusProperty() {
return memberSystemStatus;
}
Then in the Controller class I added the following code to update the GUI based on changes to each of these properties:
// heartbeatMessageProperty listener
// Update the GUI widgets when a new CAServiceHeartbeatMessage (heartbeatMessage) is updated
mListenerService.heartbeatProperty().addListener(
(ObservableValue<? extends CAServiceHeartbeatMessage> observer,
CAServiceHeartbeatMessage oldValue, CAServiceHeartbeatMessage newValue) -> {
// this is where we need to intelligently update the appropriate
// heartbeat service entries
System.out.println("updated CAServiceHeartbeatMessage");
});
// 'memberSystemMessage' bound property listener
mListenerService.memberSystemStatusProperty().addListener(
(ObservableValue<? extends MemberSystemStatusMessage> observer,
MemberSystemStatusMessage oldValue, MemberSystemStatusMessage newValue) -> {
if (newValue == null) {
. . .
My question is, how can I replace multiple SimpleObjectProperties to use a single SimpleListPropertys or an SimpleMapProperty in my JavaFX Service class. I'm not sure how, or whether I need to follow some property naming convention to expose some simple list property in my thread like I did with the 2 specific and separately named message properties. IT is probably worth noting that these messages share a common base message class - so they could be stored in a simple list type. I would also like to see an example of how I might handle the updates so that I can update the GUI when the changes occur, in particular I don'w know how to determine which of the elements in the list or map changed.
To listen to changes of the elements in your list, you can initalize the ObservableList with this factory method of FXCollections:
ObservableList<Message> messages = FXCollections.observableArrayList(message -> new Observable[] { message.messageProperty() });
Creates a new empty observable list backed by an arraylist. This list reports element updates.
or:
FXCollections.observableList(backingList, message -> new Observable[] { message.messageProperty() });
Constructs an ObservableList that is backed by the specified list. Mutation operations on the ObservableList instance will be reported to observers that have registered on that instance.
Note that mutation operations made directly to the underlying list are not reported to observers of any ObservableList that wraps it.
This list also reports mutations of the elements in it by using extractor. Observable objects returned by extractor (applied to each list element) are listened for changes and transformed into "update" change of ListChangeListener.
javadoc
public void changeListener() {
ObservableList<Message> messages = FXCollections.observableArrayList(message -> new Observable[] { message.messageProperty() });
messages.addListener((ListChangeListener<Message>) c -> {
while (c.next()) {
LOGGER.debug("change: {}", c);
if (c.wasAdded()) {
List<? extends Message> addedSubList = c.getAddedSubList();
}
if (c.wasUpdated()) {
int from = c.getFrom();
int to = c.getTo();
List<? extends Message> subList = c.getList().subList(from, to);
}
}
});
HearBeat beat = new HearBeat("beat");
messages.add(beat);
messages.add(new Status("status"));
beat.setMesssage("beat changed");
beat.setMesssage("beat changed again");
messages.addAll(new Status("1"), new Status("2"));
}
public abstract class Message {
private StringProperty message;
Message(String message) {
this.message = new SimpleStringProperty(message);
}
public StringProperty messageProperty() {
return message;
}
public String getMesssage() {
return message.get();
}
public void setMesssage(String val) {
message.set(val);
}
}
public class HearBeat extends Message {
public HearBeat(String message) {
super(message);
}
}
public class Status extends Message {
Status(String message) {
super(message);
}
}
I have three Observables which I combine with combineLastest:
Observable<String> o1 = Observable.just("1");
Observable<String> o2 = Observable.just("2");
Observable<String> o3 = Observable.just("3");
Observable.combineLatest(o1, o2, o3, new Func3<String, String, String, Object>() {
#Override
public Object call(String s, String s2, String s3) {
return null;
}
});
I want to be notified about the first emission of one of the Observables without ignoring the later emissions, which I guess first operator would do. Is there a convenient operator for that like (example):
o1.doOnFirst(new Func1<String, Void>() {
#Override
public Void call(String s) {
return null;
}
})
I think you can have a practical doOnFirst with a simple take if you're handling a stream:
public static <T> Observable<T> withDoOnFirst(Observable<T> source, Action1<T> action) {
return source.take(1).doOnNext(action).concatWith(source);
}
This way the action is only bound to the first item.
This could be changed to handle observables which are not backed by streams adding skip to skip the already taken items:
public static <T> Observable<T> withDoOnFirstNonStream(Observable<T> source, Action1<T> action) {
return source.take(1).doOnNext(action).concatWith(source.skip(1));
}
For convenience, I created these extension functions for Flowable and Observable.
Note, that with doOnFirst() the action will be called before the first element emission, whilst doAfterFirst() will firstly emit the first item and then perform the action.
fun <T> Observable<T>.doOnFirst(onFirstAction: (T) -> Unit): Observable<T> =
take(1)
.doOnNext { onFirstAction.invoke(it) }
.concatWith(skip(1))
fun <T> Flowable<T>.doOnFirst(onFirstAction: (T) -> Unit): Flowable<T> =
take(1)
.doOnNext { onFirstAction.invoke(it) }
.concatWith(skip(1))
fun <T> Observable<T>.doAfterFirst(afterFirstAction: (T) -> Unit): Observable<T> =
take(1)
.doAfterNext { afterFirstAction.invoke(it) }
.concatWith(skip(1))
fun <T> Flowable<T>.doAfterFirst(afterFirstAction: (T) -> Unit): Flowable<T> =
take(1)
.doAfterNext { afterFirstAction.invoke(it) }
.concatWith(skip(1))
Usage is as simple as this:
Flowable.fromArray(1, 2, 3)
.doOnFirst { System.err.println("First $it") }
.subscribe { println(it) }
Output:
// First 1
// 1
// 2
// 3
And:
Flowable.fromArray(1, 2, 3)
.doAfterFirst { System.err.println("First $it") }
.subscribe { println(it) }
Output:
// 1
// First 1
// 2
// 3
There are a couple of solutions I can think of.
The first one is an ugly but simple hack of doOnNext. Just add a boolean field to the Action1 indicating whether the first item has been received. Once received, do whatever it is you want to do, and flip the boolean. For example:
Observable.just("1").doOnNext(new Action1<String>() {
boolean first = true;
#Override
public void call(String t) {
if (first) {
// Do soemthing
first = false;
}
}
});
The second one is to subscribe twice on the observable you want to monitor using publish or share(), with one of those publications going through first (depending on whether you want to manually connect to the published observable). You'll end up with two separate observables that emit the same items, only the first one will stop after the first emission:
ConnectableObservable<String> o1 = Observable.just("1").publish();
o1.first().subscribe(System.out::println); //Subscirbed only to the first item
o1.subscribe(System.out::println); //Subscirbed to all items
o1.connect(); //Connect both subscribers
Using rxjava-extras:
observable
.compose(Transformers.doOnFirst(System.out::println))
It's unit tested and under the covers just uses a per-subscription counter in an operator. Note that per-subscription is important as there are plenty of uses cases where an observable instance gets used more than once and we want the doOnFirst operator to apply each time.
Source code is here.
I want to be able to create list (collection, array) filled with my own methods and in each step of iteration call the method. What's the best solution for this?
I want something like this:
List a = new List();
a.add(myCustomMethod1());
a.add(myCustomMethod2());
Object o = new Object();
for (Method m : a){
m(o);
}
In Java 8 and above you can create a List of Functional Interfaces to store the methods, as the following example shows:
// Create a list of Consumer
List<Consumer<String>> methodList= new ArrayList<>();
// Store the methods in the list
methodList.add(p -> method1(p));
methodList.add(p -> method2(p));
methodList.add(p -> method3(p));
methodList.forEach(f -> f.accept("Hello"));
Functions with no arguments you can use Runnable:
List<Runnable> methods = new ArrayList<>();
methods.add(() -> method1());
methods.add(() -> method2());
methods.add(() -> method3());
methods.forEach(f -> f.run());
In Java, you can do this with reflection by making a list of Method objects. However, an easier way is to define an interface for objects that have a method that takes an Object argument:
public interface MethodRunner {
public void run(Object arg);
}
List<MethodRunner> a = new ArrayList<>();
a.add(new MethodRunner() {
#Override
public void run(Object arg) {
myCustomMethod1(arg);
}
});
a.add(new MethodRunner() {
#Override
public void run(Object arg) {
myCustomMethod2(arg);
}
});
Object o = new Object();
for (MethodRunner mr : a) {
mr.run(o);
}