There are new convenience methods added to rxjava2 added to accomplish a similar thing.
toSingle() converts an Observable that emits a single item into a Single that emits that item
toObservable() converts a Single into an Observable that emits the item emitted by the Single and then completes
How do can I convert an Observable to a Maybe?
(source: http://reactivex.io/documentation/single.html)
You can't directly convert an Observable into a Maybe, because it wouldn't know what to emit in that context: is it the first element? the last? the product of some processing to the elements?
You can, however, decide on that and do what you want:
final Observable<Boolean> sourceBooleans = Observable.just(true, true, false);
final Maybe<Boolean> firstMaybe = sourceBooleans.firstElement();
final Maybe<Boolean> lastMaybe = sourceBooleans.lastElement();
final Maybe<Boolean> secondMaybe = sourceBooleans.elementAt(1);
final Observable<Integer> sourceNumbers = Observable.just(1, 2, 3, 4);
final Maybe<Integer> firstEven = sourceNumbers
.filter(it -> it % 2 == 0)
.firstElement()
You can see what methods return Maybe in the Observable implementation
Note that you can't go from Observable to Single directly either, without choosing what it should emit: there's no toSingle in the Observable class, but methods that return a Single instead (like first(), last(), etc.)
Related
If I have a stream that emits objects of Dog.
Stream<Dog> dogStream;
class Dog {
final String name;
final String breed;
Dog(this.name, this.breed);
}
I want to test for the name emitted in 4th value.
So I want to ignore the first 3 values emitted by the stream and check if the 4th value is equal to say foo. How to check at a particular position?
PS: There are hacky ways of doing it, like using expectInOrder, but my test should not care about the first 3 values emitted, and if I want to check for 8th or say 20th value, it doesn't make sense to use expectInOrder.
You can use elementAt or skip first 3 values of the stream and check emitted item:
test('stream', () async {
Stream<int> stream() => Stream.fromIterable([1, 2, 3, 4, 5]);
expect(await stream().elementAt(3), 4);
expect(stream().skip(3), emitsInOrder(<dynamic>[4]));
expect(stream().skip(3), emits(4));
});
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 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.
Is there a way to have an observable sequence to resume execution with the next element in the sequence if an error occurs?
From this post it looks like you need to specify a new observable sequence in Catch() to resume execution, but what if you needed to just continue processing with the next element in the sequence instead? Is there a way to achieve this?
UPDATE:
The scenario is as follows:
I have a bunch of elements that I need to process. The processing is made up of a bunch of steps. I have
decomposed the steps into tasks that I would like to compose.
I followed the guidelines for ToObservable() posted here
to convert by tasks to an observables for composition.
so basically I'm doing somethng like so -
foreach(element in collection)
{
var result = from aResult in DoAAsync(element).ToObservable()
from bResult in DoBAsync(aResult).ToObservable()
from cResult in DoCAsync(bResult).ToObservable()
select cResult;
result.subscribe( register on next and error handlers here)
}
or I could something like this:
var result =
from element in collection.ToObservable()
from aResult in DoAAsync(element).ToObservable()
from bResult in DoBAsync(aResult).ToObservable()
from cResult in DoCAsync(bResult).ToObservable()
select cResult;
What is the best way here to continue processing other elements even if let's say the processing of
one of the elements throws an exception. I would like to be able to log the error and move on ideally.
Both James & Richard made some good points, but I don't think they have given you the best method for solving your problem.
James suggested using .Catch(Observable.Never<Unit>()). He was wrong when he said that "will ... allow the stream to continue" because once you hit an exception the stream must end - that is what Richard pointed out when he mentioned the contract between observers and observables.
Also, using Never in this way will cause your observables to never complete.
The short answer is that .Catch(Observable.Empty<Unit>()) is the correct way to change a sequence from one that ends with an error to one that ends with completion.
You've hit on the right idea of using SelectMany to process each value of the source collection so that you can catch each exception, but you're left with a couple of issues.
You're using tasks (TPL) just to turn a function call into an observable. This forces your observable to use task pool threads which means that the SelectMany statement will likely produce values in a non-deterministic order.
Also you hide the actual calls to process your data making refactoring and maintenance harder.
I think you're better off creating an extension method that allows the exceptions to be skipped. Here it is:
public static IObservable<R> SelectAndSkipOnException<T, R>(
this IObservable<T> source, Func<T, R> selector)
{
return
source
.Select(t =>
Observable.Start(() => selector(t)).Catch(Observable.Empty<R>()))
.Merge();
}
With this method you can now simply do this:
var result =
collection.ToObservable()
.SelectAndSkipOnException(t =>
{
var a = DoA(t);
var b = DoB(a);
var c = DoC(b);
return c;
});
This code is much simpler, but it hides the exception(s). If you want to hang on to the exceptions while letting your sequence continue then you need to do some extra funkiness. Adding a couple of overloads to the Materialize extension method works to keep the errors.
public static IObservable<Notification<R>> Materialize<T, R>(
this IObservable<T> source, Func<T, R> selector)
{
return source.Select(t => Notification.CreateOnNext(t)).Materialize(selector);
}
public static IObservable<Notification<R>> Materialize<T, R>(
this IObservable<Notification<T>> source, Func<T, R> selector)
{
Func<Notification<T>, Notification<R>> f = nt =>
{
if (nt.Kind == NotificationKind.OnNext)
{
try
{
return Notification.CreateOnNext<R>(selector(nt.Value));
}
catch (Exception ex)
{
ex.Data["Value"] = nt.Value;
ex.Data["Selector"] = selector;
return Notification.CreateOnError<R>(ex);
}
}
else
{
if (nt.Kind == NotificationKind.OnError)
{
return Notification.CreateOnError<R>(nt.Exception);
}
else
{
return Notification.CreateOnCompleted<R>();
}
}
};
return source.Select(nt => f(nt));
}
These methods allow you to write this:
var result =
collection
.ToObservable()
.Materialize(t =>
{
var a = DoA(t);
var b = DoB(a);
var c = DoC(b);
return c;
})
.Do(nt =>
{
if (nt.Kind == NotificationKind.OnError)
{
/* Process the error in `nt.Exception` */
}
})
.Where(nt => nt.Kind != NotificationKind.OnError)
.Dematerialize();
You can even chain these Materialize methods and use ex.Data["Value"] & ex.Data["Selector"] to get the value and selector function that threw the error out.
I hope this helps.
The contract between IObservable and IObserver is OnNext*(OnCompelted|OnError)? which is upheld by all operators, even if not by the source.
Your only choice is to re-subscribe to the source using Retry, but if the source returns the IObservable instance for every description you won't see any new values.
Could you supply more information on your scenario? Maybe there is another way of looking at it.
Edit: Based on your updated feedback, it sounds like you just need Catch:
var result =
from element in collection.ToObservable()
from aResult in DoAAsync(element).ToObservable().Log().Catch(Observable.Empty<TA>())
from bResult in DoBAsync(aResult).ToObservable().Log().Catch(Observable.Empty<TB>())
from cResult in DoCAsync(bResult).ToObservable().Log().Catch(Observable.Empty<TC>())
select cResult;
This replaces an error with an Empty which would not trigger the next sequence (since it uses SelectMany under the hood.