I'm using a PublishSubject along with map operator:
#Test
public void testMapWithMultipleObservers() {
PublishSubject<Integer> subject = PublishSubject.create();
Func1 action = spy(new Func1<Integer, Integer>() {
#Override
public Integer call(Integer integer) {
return integer;
}
});
Observable<Integer> observable = subject.asObservable().map(action);
observable.subscribe(mock(Observer.class));
observable.subscribe(mock(Observer.class));
subject.onNext(1);
verify(action, times(2)).call(anyInt());
// however, I need it to be times(1)
}
The desired behaviour is to perform an action after the subject produces a value. I've tried doOnEach,doOnNext, map and in each case the action is performed for each present observer (for 100 observers action would be performed 100 times), while I need it to perform per emission.
Could you suggest anything?
Thanks.
The quickest option would be to use share()
Observable<Integer> observable =
subject
.map(action)
.share();
You don't need the asObservable() call. It is used to return a Subject from an API and prevent the caller from casting it back to a Subject. For example:
Observable<Integer> getSubjectAsObservable() {
return subject.asObservable();
}
Related
I'm kind of new to reactive programing and currently working on a spring webflux based application. I'm stuck between few questions.
public class FooServiceImpl {
#Autowired
private FooDao fooDao;
#Autowired
private AService aService;
#Autowired
private BService bService;
public long calculateSomething(long fooId) {
Foo foo = fooDao.findById(fooId); // Blocking call one
if (foo == null) {
foo = new Foo();
}
Long bCount = bService.getCountBByFooId(fooId); // Blocking call two
AEntity aEntity = aService.getAByFooId(fooId); // Blocking call three
// Do some calculation using foo, bCount and aEntity
// ...
// ...
return someResult;
}
}
This is the way we write a blocking code which uses three external API call results (let's consider as DB calls). I'm struggling to convert this into a reactive code, If all three becomes mono and if I subscribe all three will the outer subscriber get blocked?
public Mono<Long> calculateSomething(long fooId) {
return Mono.create(sink -> {
Mono<Foo> monoFoo = fooDao.findById(fooId); // Reactive call one
monoFoo.subscribe(foo -> {
if (foo == null) {
foo = new Foo();
}
Mono<Long> monoCount = bService.getCountBByFooId(fooId); // Reactive call two
monoCount.subscribe(aLong -> {
Mono<AEntity> monoA = aService.getAByFooId(fooId); // Reactive call three
monoA.subscribe(aEntity -> {
//...
//...
sink.success(someResult);
});
});
});
};
}
I saw there is a function called zip, but it only works with two results, So is there a way to apply it here?
Also what will happen if we get subscribe for something inside create method, Will it block the thread?
Would be very thankful if you could help me.
If you gave me the calculation you want you do with those values, it would be easier for me to show the reactor way of doing it. But lets suppose you want to read a value from database and then use that value for another thing. Use flatmaps and make a unique Flux reducing the lines of code and complexity, no need to use subscribe() as told by the other people. Example:
return fooDao.findById(fooId)
.flatmap(foo -> bService.getCountBByFooId(foo))
.flatmap(bCount -> aService.getAByFooId(fooId).getCount()+bCount);
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 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
I have heard several reactive programming folks say "don't break the monad, just continue it". I see the merit in this. There are still certain instances I'm confused about, especially when the Observable is finally consumed or subscribed to. This is even more confusing when several observables have to be consumed at once, and it doesn't feel very practical to combine them into a single observable.
Let's say for instance I have a TrackedAircraft type. Some of its properties are final while other properties are Observable.
public interface TrackedAircraft {
public int getFlightNumber();
public int getCapacity();
public Observable<String> getOrigin();
public Observable<String> getDestination();
public Observable<Integer> getMileage();
public Observable<Point> getLocation();
}
I could wire this to a GUI pretty easily, and just subscribe controls to be updated with each emission of each property. But what about an email or a body of static text? This is not as straightforward because the only way I can think of not breaking the monad is to combine all the observables which sounds like a pain especially if I have an Observable emitting TrackedFlights.
Is it okay to block in this situation? Or is there a more monadic way to accomplish this I haven't thought of?
public static String generateEmailReportForFlight(TrackedAircraft flight) {
return new StringBuilder().append("FLIGHT NUMBER: ").append(flight.getFlightNumber()).append("\r\n")
.append("CAPACITY: ").append(flight.getCapacity()).append("\r\n")
.append("ORIGIN: ").append(flight.getOrigin() /*What do I do here without blocking?*/)
.append("DESTINATION: ").append(flight.getDestination() /*What do I do here without blocking?*/)
.append("MILEAGE: ").append(flight.getMileage() /*What do I do here without blocking?*/)
.append("LOCATION: ").append(flight.getLocation() /*What do I do here without blocking?*/)
.toString();
}
///
Observable<TrackedAircraft> trackedFlights = ...;
trackedFlights.map(f -> generateEmailReportForFlight(f));
You can use flatMap + combineLatest:
Observable<TrackedAircraft> trackedFlights = ...
trackedFlights
.flatMap(flight -> emailReport(flight))
.subscribe(msg -> sendEmail(msg));
Observable<String> emailReport(TrackedAircraft flight) {
return Observable.combineLatest(
flight.getOrigin(),
flight.getDestination(),
flight.getMileage(),
flight.getLocation()
(origin, destination, mileage, location) -> {
return new StringBuilder()
.append("FLIGHT NUMBER: ").append(flight.getFlightNumber())
.append("\r\n")
.append("CAPACITY: ").append(flight.getCapacity())
.append("\r\n")
.append("ORIGIN: ").append(origin)
.append("\r\n")
.append("DESTINATION: ").append(destination)
.append("\r\n")
.append("MILEAGE: ").append(mileage)
.append("\r\n")
.append("LOCATION: ").append(location)
.toString();
}
)
}
I have na event-based API (Geolocator) that I want to convert to Rx.
The problem is that some operations require that all events are unsubscribed and I don't want to pass that burdon to the user of the Rx API.
So, the user will subscribe to a few observables and when the events are subscribed they are published to those observables.
What's the best way to do this?
I thought of creating a subject that the users subscribe to and then have the events published to those through another set of observables.
Is this the best way? If so, how?
The key problem is to find a way to keep an Observer subscribed to a stream whilst tearing down and replacing an underlying source. Let's just focus on a single event source - you should be able to extrapolate from that.
First of all, here is an example class we can use that has a single event SomeEvent that follows the standard .NET pattern using an EventHandler<StringEventArgs> delegate. We will use this to create sources of events.
Note I have intercepted the event add/remove handlers in order to show you when Rx subscribes and unsubscribes from the events, and given the class a name property to let us track different instances:
public class EventSource
{
private string _sourceName;
public EventSource(string sourceName)
{
_sourceName = sourceName;
}
private event EventHandler<MessageEventArgs> _someEvent;
public event EventHandler<MessageEventArgs> SomeEvent
{
add
{
_someEvent = (EventHandler<MessageEventArgs>)
Delegate.Combine(_someEvent, value);
Console.WriteLine("Subscribed to SomeEvent: " + _sourceName);
}
remove
{
_someEvent = (EventHandler<MessageEventArgs>)
Delegate.Remove(_someEvent, value);
Console.WriteLine("Unsubscribed to SomeEvent: " + _sourceName);
}
}
public void RaiseSomeEvent(string message)
{
var temp = _someEvent;
if(temp != null)
temp(this, new MessageEventArgs(message));
}
}
public class MessageEventArgs : EventArgs
{
public MessageEventArgs(string message)
{
Message = message;
}
public string Message { get; set; }
public override string ToString()
{
return Message;
}
}
Solution Key Idea - StreamSwitcher
Now, here is the heart of the solution. We will use a Subject<IObservable<T>> to create a stream of streams. We can use the Observable.Switch() operator to return only the most recent stream to Observers. Here's the implementation, and an example of usage will follow:
public class StreamSwitcher<T> : IObservable<T>
{
private Subject<IObservable<T>> _publisher;
private IObservable<T> _stream;
public StreamSwitcher()
{
_publisher = new Subject<IObservable<T>>();
_stream = _publisher.Switch();
}
public IDisposable Subscribe(IObserver<T> observer)
{
return _stream.Subscribe(observer);
}
public void Switch(IObservable<T> newStream)
{
_publisher.OnNext(newStream);
}
public void Suspend()
{
_publisher.OnNext(Observable.Never<T>());
}
public void Stop()
{
_publisher.OnNext(Observable.Empty<T>());
_publisher.OnCompleted();
}
}
Usage
With this class you can hook up a new stream on each occasion you want to start events flowing by using the Switch method - which just sends the new event stream to the Subject.
You can unhook events using the Suspend method, which sends an Observable.Never<T>() to the Subject effectively pausing the flow of events.
Finally you can stop altogether by called to Stop to push an Observable.Empty<T>() andOnComplete()` the subject.
The best part is that this technique will cause Rx to do the right thing and properly unsubscribe from the underlying event sources each time you Switch, Suspend or Stop. Note also, that once Stopped no more events will flow, even if you Switch again.
Here's an example program:
static void Main()
{
// create the switch to operate on
// an event type of EventHandler<MessageEventArgs>()
var switcher = new StreamSwitcher<EventPattern<MessageEventArgs>>();
// You can expose switcher using Observable.AsObservable() [see MSDN]
// to hide the implementation but here I just subscribe directly to
// the OnNext and OnCompleted events.
// This is how the end user gets their uninterrupted stream:
switcher.Subscribe(
Console.WriteLine,
() => Console.WriteLine("Done!"));
// Now I'll use the example event source to wire up the underlying
// event for the first time
var source = new EventSource("A");
var sourceObservable = Observable.FromEventPattern<MessageEventArgs>(
h => source.SomeEvent += h,
h => source.SomeEvent -= h);
// And we expose it to our observer with a call to Switch
Console.WriteLine("Subscribing");
switcher.Switch(sourceObservable);
// Raise some events
source.RaiseSomeEvent("1");
source.RaiseSomeEvent("2");
// When we call Suspend, the underlying event is unwired
switcher.Suspend();
Console.WriteLine("Unsubscribed");
// Just to prove it, this is not received by the observer
source.RaiseSomeEvent("3");
// Now pretend we want to start events again
// Just for kicks, we'll use an entirely new source of events
// ... but we don't have to, you could just call Switch(sourceObservable)
// with the previous instance.
source = new EventSource("B");
sourceObservable = Observable.FromEventPattern<MessageEventArgs>(
h => source.SomeEvent += h,
h => source.SomeEvent -= h);
// Switch to the new event stream
Console.WriteLine("Subscribing");
switcher.Switch(sourceObservable);
// Prove it works
source.RaiseSomeEvent("3");
source.RaiseSomeEvent("4");
// Finally unsubscribe
switcher.Stop();
}
This gives output like this:
Subscribing
Subscribed to SomeEvent: A
1
2
Unsubscribed to SomeEvent: A
Unsubscribed
Subscribing
Subscribed to SomeEvent: B
3
4
Unsubscribed to SomeEvent: B
Done!
Note it doesn't matter when the end user subscribes - I did it up front, but they can Subscribe any time and they'll start getting events at that point.
Hope that helps! Of course you'll need to pull together the various event types of the Geolocator API into a single convenient wrapper - but this should enable you to get there.
If you have several events you want to combine into a single stream using this technique, look at operators like Merge, which requires you to project the source streams into a common type, with Select maybe, or something like CombineLatest - this part of the problem shouldn't be too tricky.
This is what I came up with.
I have created two subjects for the clients of my API to subscribe:
private readonly Subject<Geoposition> positionSubject = new Subject<Geoposition>();
private readonly Subject<PositionStatus> statusSubject = new Subject<PositionStatus>();
And observables for the events my API is subscribing to:
private IDisposable positionObservable;
private IDisposable statusObservable;
When I want to subscribe to the events, I just subscribe them into the subjects:
this.positionObservable = Observable
.FromEvent<TypedEventHandler<Geolocator, PositionChangedEventArgs>, PositionChangedEventArgs>(
conversion: handler => (s, e) => handler(e),
addHandler: handler => this.geolocator.PositionChanged += handler,
removeHandler: handler => this.geolocator.PositionChanged -= handler)
.Select(e => e.Position)
.Subscribe(
onNext: this.positionSubject.OnNext,
onError: this.positionSubject.OnError);
this.statusObservable = Observable
.FromEvent<TypedEventHandler<Geolocator, StatusChangedEventArgs>, StatusChangedEventArgs>(
conversion: handler => (s, e) => handler(e),
addHandler: handler => this.geolocator.StatusChanged += handler,
removeHandler: handler => this.geolocator.StatusChanged -= handler)
.Select(e => e.Status)
.Subscribe(
onNext: this.statusSubject.OnNext,
onError: this.statusSubject.OnError);
When I want to cancel the subscription, I just dispose of the subscriptions:
this.positionObservable.Dispose();
this.statusObservable.Dispose();