I have this the following scenario I need to achieve:
perform each network call for a list of request object with 1 second delay each
and I have this following implementation using rxjava2
emit an interval stream
emit an iterable stream
zip them to emit each item from the iterable source
which by far has no problem and I fully understand how it works, now I integrated the above to the following
map each item emitted from zip into a new observable that defer/postpone an observable source for a network call
each mapped-emitted observable will perform an individual network call for each request
which I ended up with the following code
Observable
.zip(Observable.interval(1, TimeUnit.SECONDS), Observable.fromIterable(iterableRequests), new BiFunction<Long, RequestInput, RequestResult>() {
#Override
public RequestResult apply(#NonNull Long aLong, #NonNull final RequestInput request) throws Exception {
return request;
}
})
.map(new Function<RequestResult, ObservableSource<?>>() {
#Override
public ObservableSource<?> apply(#NonNull RequestResult requestResult) throws Exception {
// map each requestResult into this observable and perform a new stream
return Observable
.defer(new Callable<ObservableSource<?>>() {
// return a postponed observable for each subscriber
})
.retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
// return throwable observable
})
}
})
.subscribe(new Observer<ObservableSource<?>>() {
//.. onSubscribe {}
//.. onError {}
//.. onComplete {}
#Override
public void onNext(ObservableSource<?> observableSource) {
// actual subscription for each of the Observable.defer inside
// so it will start to emit and perform the necessary operation
}
});
but the problem is, it executes the Observable.defer source, only ONCE, but keeps on iterating(by putting a Log inside the map operator to see the iteration).
Can anyone guide me please on how can I achieve what I want, I exhausted alot of papers, drawing alot of marble diagrams, just to see where Im at on my code,
I dont know if the diagram I created illustrate the thing that I want, if it does, I dont know why does the sample code dont perform as the diagram portraits
Any help would be greatly appreciated.
The first part is fine, but the map thingy is a bit unneeded, what you are doing is mapping each RequestResult to an Observable, and then manually subscribe to it at the Observer.onNext(), actually the defer is not necessary as you're creating separate Observable for each RequestResult with different data, defer will occur at each subscribe yoy do at onNext(), and the map occur as you observed for each emission of the zipped RequestResult.
what you probably need is simple flatMap() to map each RequestResult value to a separate Observable that will do the network request, and it will merge back the result for each request to the stream, so you'll just need to handle the final values emission for each request instead to subscribe manually to each Observable.
Just keep in mind that order might be lost, in case some requests might take longer than your delay between them.
Observable.zip(Observable.interval(1, TimeUnit.SECONDS), Observable.fromIterable(iterableRequests),
new BiFunction<Long, RequestInput, RequestResult>() {
#Override
public RequestResult apply(#NonNull Long aLong,
#NonNull final RequestInput request) throws Exception {
return request;
}
})
.flatMap(new Function<RequestResult, ObservableSource<?>>() {
#Override
public ObservableSource<?> apply(RequestResult requestResult) throws Exception {
return createObservableFromRequest(requestResult)
.retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
// return throwable observable
})
}
})
.subscribe(new Observer<ObservableSource<?>>() {
//.. onSubscribe {}
//.. onError {}
//.. onComplete {}
#Override
public void onNext(ObservableSource<?> observableSource) {
//do something with each network result request emission
}
});
I manage to make it work, as somewhere inside the Observable.defer, my retrofitclient was null,
retrofitClient.getApiURL().post(request); // client was null
my retrofitClient was null ( i looked somewhere in the code and I noticed i was not initialized, and I initialized it properly and made it work)
now can anybody tell me why Rx didnt throw an exception back to the original observable stream? theres no NullPointerException that occurred, Im confused
Related
We have been using the Context object to in a long chain of async execution.
e.g.:
private void checkVehicle(final JsonObject cmd,
final RedisFleetStorage storage,
final Handler<AsyncResult<String>> handler) {
// omitted for brevity
// some async call to another verticle
storage.getVehicle(fleetId, vehicleId, result -> {
if (!result.succeeded()) {
LOG.error(String.format("Impossible to get vehicleStatus %s:%s", fleetId, vehicleId), result.cause());
handler.handle(Future.failedFuture("KO");
return;
}
// put vehicle in context for later use
final Vehicle vehicle = result.result();
LOG.info("vehicle details {}", vehicle);
context.put("vehicle", vehicle);
handler.handle(Future.succeededFuture());
});
}
As seen above, we put an object (vehicle) in the context and then access later in the execution.
But we suspect that the vehicle object it's altered by another execution. Is it possible? Can another event-loop change the object in the context?
A verticle instance handles all requests with the same event loop.
This why the Context object is not suited for storage of request specific data.
I want to fuse the inputs of several Android sensors and expose the output as an observable (or at least something that can be subscribed to) that supports multiple simultaneous observers. What's the idiomatic way to approach this? Is there a class in the standard library that would make a good starting point?
I was thinking of wrapping a PublishSubject in an object with delegates for one or more subscribe methods that test hasObservers to activate the sensors, and wrap the returned Disposable in a proxy that tests hasObservers to deactivate them. Something like this, although this already has some obvious problems:
public class SensorSubject<T> {
private final PublishSubject<T> mSubject = PublishSubject.create();
public Disposable subscribe(final Consumer<? super T> consumer) {
final Disposable d = mSubject.subscribe(consumer);
if(mSubject.hasObservers()) {
// activate sensors
}
return new Disposable() {
#Override
public void dispose() {
// possible race conditions!
if(!isDisposed()) {
d.dispose();
if(!mSubject.hasObservers()) {
// deactivate sensors
}
}
}
#Override
public boolean isDisposed() {
return d.isDisposed();
}
};
}
}
The idiomatic way to do that in RxJava would be to use hot observable.
Cold observables do some action when someone subscribes to them and emit all items to that subscriber. So it's 1 to 1 relation.
Hot observable do some action and emits items independently on individual subscription. So if you subscribe too late, you might not get some values that were emitted earlier. This is 1 to many relation, aka multicast - which is what you want.
Usual way to do it is Flowable.publish() which makes Flowable multicast, but requires calling connect() method to start emitting values.
In your case you can also call refCount() which adds your desired functionality - it subscribes to source Flowable when there is at least one subscription and unsubscribes when everyone unsubsribed.
Because publish().refCount() is pretty popular combination, there is a shortcut for them - share(). And as far as I understand this is exactly what you want.
Edit by asker: This code incorporates this answer and David Karnok's comment in the form of a Dagger 2 provider method. SimpleMatrix is from EJML. This seems to be doing what I asked for.
#Provides
#Singleton
#Named(MAGNETOMETER)
public Observable<SimpleMatrix> magnetometer(final SensorManager sensorManager) {
final PublishSubject<SimpleMatrix> ps = PublishSubject.create();
final Sensor sensor = sensorManager.getDefaultSensor(TYPE_MAGNETIC_FIELD);
final SensorEventListener listener = new SensorEventAdapter() {
#Override
public void onSensorChanged(final SensorEvent event) {
ps.onNext(new SimpleMatrix(1, 3, true, event.values));
}
};
return ps.doOnSubscribe(s -> {
sensorManager.registerListener(listener, sensor, SENSOR_DELAY_NORMAL);
}).doOnDispose(() -> {
sensorManager.unregisterListener(listener);
}).share();
}
I'm using RxJava in and Android application with RxAndroid. I'm using mergeDelayError to combine two retro fit network calls into one observable which will process emitted items if either emits one and the error if either has one. This is not working and it is only firing off the onError action when either encounters an error. Now to test this I shifted to a very simple example and still the successAction is never called when I have an onError call. See example below.
Observable.mergeDelayError(
Observable.error(new RuntimeException()),
Observable.just("Hello")
)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.finallyDo(completeAction)
.subscribe(successAction, errorAction);
The success action will only be called if I use two success observables. Am I missing something with how mergeDelayError is supposed to work?
EDIT:
I've found that if I remove the observeOn and subscribeOn everything works as expected. I need to specify threads and thought that was the whole point of using Rx. Any idea why specifying those Schedulers would break the behavior?
Use .observeOn(AndroidSchedulers.mainThread(), true) instead of .observeOn(AndroidSchedulers.mainThread()
public final Observable<T> observeOn(Scheduler scheduler, boolean delayError) {
return observeOn(scheduler, delayError, RxRingBuffer.SIZE);
}
Above is the signature of observeOn function. Following code works.
Observable.mergeDelayError(
Observable.error(new RuntimeException()),
Observable.just("Hello")
)
.observeOn(AndroidSchedulers.mainThread(), true)
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<String>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String s) {
}
});
Got this trick from ConcatDelayError thread: https://github.com/ReactiveX/RxJava/issues/3908#issuecomment-217999009
This still seems like a bug in the mergeDelayError operator but I was able to get it working by duplicating the observerOn and Subscribe on for each observable.
Observable.mergeDelayError(
Observable.error(new RuntimeException())
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io()),
Observable.just("Hello")
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
)
.finallyDo(completeAction)
.subscribe(successAction, errorAction);
I think you don't wait for the terminal event and the main thread quits before the events are delivered to your observer. The following test passes for me with RxJava 1.0.14:
#Test
public void errorDelayed() {
TestSubscriber<Object> ts = TestSubscriber.create();
Observable.mergeDelayError(
Observable.error(new RuntimeException()),
Observable.just("Hello")
)
.subscribeOn(Schedulers.io()).subscribe(ts);
ts.awaitTerminalEvent();
ts.assertError(RuntimeException.class);
ts.assertValue("Hello");
}
i am using the following rxjava dependencies in android:
compile 'io.reactivex.rxjava2:rxjava:2.1.0'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
and i am trying to create a method that will take in a observer as a paramter. I am having some issues i think its because this is rxjava2 so things are updated and im a little confused.
Let me show you what i want to accomplish:
private Subscription subscription = Scriptions.empty(); //this isn't working. how to set a empty observer IN RXJAVA2?
protected abstract Observable buildUseCaseObservable(); //RETROFIT WILL BUILD THE OBSERVABLE FOR ME SOMEWHERE ELSE
public void execute(Consumer UseCaseSubscriber){
this.subscription = this.buildUseCaseObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(UseCaseSubscriber); //THIS LINE IS NOT WORKING , ERROR IS IN THE PHOTO
}
public void unsubscribe(){
if(!subscription.isUnsubscribed()){
subscription.unsubscribe();
}
}
Basically i am trying to create a method that will accept a observer/consumer as parameter and use that to update the UI after retrofit is done (being the observable).
UPDATE:
ok i changed it to disposables. now i'd like to store the disposable that i get back but its not working.
protected abstract Observable buildUseCaseObservable();
#SuppressWarnings("unchecked")
public void execute(Observer UseCaseSubscriber){
this.subscription = this.buildUseCaseObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(UseCaseSubscriber);
}
public void unsubscribe(){
if(!subscription.isUnsubscribed()){
subscription.unsubscribe();
}
}
i am getting the following warning:
The reason i want to store the whole thing in a subscription (or whatever else you recommend) is so i can unsubscribe to it whenever i want.
but from the docs:
Because Reactive-Streams base interface, org.reactivestreams.Publisher defines the subscribe() method as void, Flowable.subscribe(Subscriber) no longer returns any Subscription (or Disposable). The other base reactive types also follow this signature with their respective subscriber types.
so how to save disposable so we can unsubscribe then ?
Subscription has been 'renamed' to Disposable with 2.x version. You can read the rxJava wiki explanation on this change here.
so how to save disposable so we can unsubscribe then ? Flowable.subscribe(Subscriber) doesn't return disposable, but Observable.subscribe(Subscriber) does. If you don't need back-pressure, just cast your Flowable to Observable with .toObservable().
Playing with RxJava now and stumbled upon the following problem:
I have 2 different streams:
Stream with items
Stream (with just 1 item) which emits transformation information for the first stream.
So essentially I have stream of items and I want all those items to be combined with that single item from 2nd stream:
----a1----a2----a3----a4----a5----|--------------->
-------------b1--|----------------------------------->
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
------------a1b1-a2b1-a3b1-a4b1-a5b1-------->
It looks really similar to combileLatest operator, but combineLatest will ignore all items from the first stream except the closest to the item from the second stream. It means that I will not receive a1b1 - the first resulting item emitted is gonna be a2b1.
I also looked at delay operator, but it doesn't allow me to specify close stream like it is done with buffer operatior
Is there any fancy operator which solves the problem above?
There are several ways of making this happen:
1) flatMap over b if you don't need to start a upfront
b.flatMap(bv -> a.map(av -> together(av, bv)));
2) You can, of course, cache but it will retain your as for the entire duration of the stream.
3) Use groupBy a bit unconventionally because its GroupedObservable caches values until the single subscriber arrives, replays the cached value and continues as a regular direct observable (letting all previous cached values go).
Observable<Long> source = Observable.timer(1000, 1000, TimeUnit.MILLISECONDS)
.doOnNext(v -> System.out.println("Tick"))
.take(10);
Observable<String> other = Observable.just("-b").delay(5000, TimeUnit.MILLISECONDS)
.doOnNext(v -> System.out.println("Tack"))
;
source.groupBy(v -> 1)
.flatMap(g ->
other.flatMap(b -> g.map(a -> a + b))
).toBlocking().forEach(System.out::println);
It works as follows:
Get a hold onto a GroupedObservable by grouping everything from source into group 1.
when the group g arrives, we 'start observing' the other observable.
Once other fires its element, we take it and map it over the group and 'start observing' it as well, bringing us the final sequence of a + bs.
I've added doOnNexts so you can see the source is really active before the other fires its "Tack".
AFAIK, there is no a built-in operator to achieve the behavior you've described. You can always implement a custom operator or build it on top of existing operators. I think the second option is easier to implement and here is the code:
public static <L, R, T> Observable<T> zipper(final Observable<? extends L> left, final Observable<? extends R> right, final Func2<? super L, ? super R, ? extends T> function) {
return Observable.defer(new Func0<Observable<T>>() {
#Override
public Observable<T> call() {
final SerialSubscription subscription = new SerialSubscription();
final ConnectableObservable<? extends R> cached = right.replay();
return left.flatMap(new Func1<L, Observable<T>>() {
#Override
public Observable<T> call(final L valueLeft) {
return cached.map(new Func1<R, T>() {
#Override
public T call(final R valueRight) {
return function.call(valueLeft, valueRight);
}
});
}
}).doOnSubscribe(new Action0() {
#Override
public void call() {
subscription.set(cached.connect());
}
}).doOnUnsubscribe(new Action0() {
#Override
public void call() {
subscription.unsubscribe();
}
});
}
});
}
If you have any questions regarding the code, I can explain it in details.
UPDATE
Regarding the questing how my solution is different from the following one:
left.flatMap(valueLeft -> right.map(valueRight -> together(valueLeft, valueRight)));
Parallel execution - in my implementation both left and right observables are executing in parallel. right observable doesn't have to wait for a left one to emit its first item.
Caching - my solution subscribes only once to the right observables and caches its result. Thats why b1 will always be the same for all aXXX items. The solution provided by akarnokd subscribes to the rightobservable every time the left one emits an item. That means:
There is no guarantee that b1 won't change its value. For example for the following observable you will get a different b for each a.
final Observable<Double> right = Observable.defer(new Func0<Observable<Double>>() {
#Override
public Observable<Double> call() {
return Observable.just(Math.random());
}
});
If the right observable is a time consuming operation (e.g. network call), you will have to wait for its completion every time the left observable emits a new item.