Is there any problem in subscribe an observable's subscriber to another observable?
That is something like:
Observable.create((Subscriber<? super Response> subscriber) -> {
Observable<T1> o1 = createObservableT1(location); //Hot observable
Observable<T2> o2 = createObservableT2(location); //Hot observable
Observable.zip(o1,o2,(T1 r1, T2 r2) -> {
return createResponse(r1,r2);
}).subscribe(subscriber); //Subscribe our subscriber to the created observable
});
Is it a good pattern or there are some hidden drawbacks?
If there is some drawbacks how can I do it taking in account that o1, and o2 are hot observables that need to be combined to create the returned Observable that has to be mantained as a cold one.
I cannot find any problem. But I would recommend defer, such as
Observable.defer(
() -> createObservableT1(location)
.zipWith(createObservableT2(location),
(r1, r2) -> createResponse(r1, r2)));
Related
I need to filter a Stream of observable Values based on some condition which is modeled as Observable inside my Value.
class ValueObject {
BehaviorSubject<Boolean> condition = ...;
}
...
valueObjects.filter(valueObject -> condition).subscribe(valueObject -> ...);
My goal is to have the stream firing if a) a new Value was pushed or b) the condition for the filter changed.
(Bonus: do that same thing with lists of ValueObjects (Observable<List<ValueObject>>) and that ugly Object[]-combineLatest...)
Is there some kind of best practice for that problem? Thanks.
I'm trying to create an Observable with the following characteristics:
allows multiple concurrent and/or consecutive subscribers
emits the last emitted item to every new subscriber
does something when the first subscriber subscribes, and when the last subscription is disposed
A BehaviorSubject with doOnSubscribe/doOnDispose satisfies #1 and #2, but runs subscribe/dispose for every subscriber instead of only the first and last. Adding share satisfies #1 and #3, but only emits the last emitted item to the first concurrent subscriber.
I came up with a solution that seems to work but feels like an ugly hack:
AtomicInteger subs = new AtomicInteger();
Observable<String> test = BehaviorSubject.createDefault("foo")
.doOnSubscribe(x -> {
if(subs.getAndIncrement() == 0) {
// do something
}
})
.doOnDispose(() -> {
if(subs.decrementAndGet() == 0) {
// do something
}
});
Is there an existing operator or combination of operators that achieves the same effect?
Use the replay operator with argument 1 i.e.
yourObservable.replay(1)
Edit: You are right that replay will return a connectedObservable and that the refcount operator will make it behave like on Observable i.e.
yourObservable.replay(1).refcount()
I'm trying to get a subscription to automatically unsubscribe when it emits an item. The base observable is created like this.
public static Observable<RxBleConnection> setupConnection(RxBleDevice device, PublishSubject<Void> disconnectTrigger) {
return device
.establishConnection(false)
.takeUntil(disconnectTrigger)
.retry(3)
.retryWhen(o -> o.delay(RETRY_DELAY, TimeUnit.MILLISECONDS))
.compose(new ConnectionSharingAdapter());
}
Then I try to combine three read operations into a ProgramModel.
private void readCharacteristics(Action1<ProgramModel> onReadSuccess) {
mConnectionObservable
.flatMap(rxBleConnection ->
// combines the following three observables into a single observable that is
// emitted in onNext of the subscribe
Observable.combineLatest(
rxBleConnection.readCharacteristic(UUID_SERIAL_NUMBER),
rxBleConnection.readCharacteristic(UUID_MACHINE_TYPE),
rxBleConnection.readCharacteristic(UUID_CHARACTERISTIC),
ProgramModel::new))
.observeOn(AndroidSchedulers.mainThread())
.take(1)
.subscribe(programModel -> {
programModel.trimSerial();
onReadSuccess.call(programModel);
}, BleUtil::logError);
}
So theoretically once a program model is comes through oNext of the subscribe, the subscription will be unsubscribed from. For some reason the operation gets stuck and onNext and onError are never called. If I remove the take(1) this works fine but I don't want to have to deal with holding onto a reference to the subscription and unsubscribing manually. Does anyone know what I'm doing wrong or why onNext is not being called?
I needed to call take(1) before the flatMap as well as after. This post sort of explains it Read multiple characteristics from an Android device using library RxAndroidBle
i'm a RxJava newcomer, and i'm having some trouble wrapping my head around how to do the following.
i'm using Retrofit to invoke a network request that returns me a Single<Foo>, which is the type i ultimately want to consume via my Subscriber instance (call it SingleFooSubscriber)
Foo has an internal property items typed as List<String>.
if Foo.items is not empty, i would like to invoke separate, concurrent network requests for each of its values. (the actual results of these requests are inconsequential for SingleFooSubscriber as the results will be cached externally).
SingleFooSubscriber.onComplete() should be invoked only when Foo and all Foo.items have been fetched.
fetchFooCall
.subscribeOn(Schedulers.io())
// Approach #1...
// the idea here would be to "merge" the results of both streams into a single
// reactive type, but i'm not sure how this would work given that the item emissions
// could be far greater than one. using zip here i don't think it would every
// complete.
.flatMap { foo ->
if(foo.items.isNotEmpty()) {
Observable.zip(
Observable.fromIterable(foo.items),
Observable.just(foo),
{ source1, source2 ->
// hmmmm...
}
).toSingle()
} else {
Single.just(foo)
}
}
// ...or Approach #2...
// i think this would result in the streams for Foo and items being handled sequentially,
// which is not really ideal because
// 1) i think it would entail nested streams (i get the feeling i should be using flatMap
// instead)
// 2) and i'm not sure SingleFooSubscriber.onComplete() would depend on the completion of
// the stream for items
.doOnSuccess { data ->
if(data.items.isNotEmpty()) {
// hmmmm...
}
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ data -> /* onSuccess() */ },
{ error -> /* onError() */ }
)
any thoughts on how to approach this would be greatly appreciated!
bonus points: in trying to come up with a solution to this, i've begun to question the decision to use the Single reactive type vs the Observable reactive type. most (all, except this one Foo.items case?) of my streams actually revolve around consuming a single instance of something, so i leaned toward Single to represent my streams as i thought it would add some semantic clarity around the code. anybody have any general guidance around when to use one vs the other?
You need to nest flatMaps and then convert back to Single:
retrofit.getMainObject()
.flatMap(v ->
Flowable.fromIterable(v.items)
.flatMap(w ->
retrofit.getItem(w.id).doOnNext(x -> w.property = x)
)
.ignoreElements()
.toSingle(v)
)
I have collection of INotifyPropertyChanged objects and would like to stream all PropertyChanged events into a single observable sequence for further processing.
Here is a code
IObservable<EventPattern<PropertyChangedEventArgs>> _allEvents = null;
// Items contains collection of item, which implements INotifyPropertyChanged
foreach (var item in Items)
{
var seq = Observable.FromEventPattern<PropertyChangedEventArgs>(item, "PropertyChanged");
if (_allEvents == null)
_allEvents = seq;
else
_allEvents.Merge(seq);
}
// subscribe to the aggregated observable sequence
if (_allEvents != null)
_allEvents.Subscribe(evt => Trace.WriteLine(" Property Changed -> " + evt.EventArgs.PropertyName));
A single Subscribe doesn't work here for some reason in the aggregated sequence.
Looks like I aggregated (using Reactive Extensions's Merge function) incorrectly. But, subscribe inside the loop works perfectly.
Can anybody assist me here, how to aggregate a many event streams into one with reactive extensions?
Thanks
Try this:
var _allEvents = Observable
.Merge(Items
.Select(item => Observable
.FromEventPattern<PropertyChangedEventArgs>(item, "PropertyChanged")));
_allEvents.Subscribe(evt => Trace.WriteLine(" Property Changed -> " + evt.EventArgs.PropertyName));
The reason your approach doesn't work is that you were calling IObservable<T> Observable.Merge<T>(this IObservable<T> first, IObservable<T> second). The return type of this is a resulting observable. I think you might have been thinking that Merge modified the Observable, but you can think of Observables as immutable (sort of). The way to get your approach to work would have been:
_allEvents = _allEvents.Merge(seq);
But... yuck. Don't do that.