Why does my RxJava Observable emit only to the first consumer? - java

Can someone explain why the below test fails?
public class ObservableTest {
#Test
public void badObservableUsedTwiceDoesNotEmitToSecondConsumer() {
// Any simpler observable makes the test pass
Observable<Integer> badObservable = Observable.just(1)
.zipWith(Observable.just(2), (one, two) -> Observable.just(3))
.flatMap(observable -> observable);
ObservableCalculator calc1 = new ObservableCalculator(badObservable);
ObservableCalculator calc2 = new ObservableCalculator(badObservable);
// zipping causes the failure
// Calling calculate().toBlocking().subscribe() on each calc passes
// Observable.from(listOfCalcs).flatMap(calc -> calc.calculate()) passes
Observable.zip(ImmutableList.of(calc1.calculate(), calc2.calculate()), results -> results)
.toBlocking()
.subscribe();
assertThat(calc1.hasCalculated).isTrue();
assertThat(calc2.hasCalculated).isTrue(); // this fails
}
private static class ObservableCalculator {
private final Observable<?> observable;
public boolean hasCalculated = false;
public ObservableCalculator(Observable<?> observable) {
this.observable = observable;
}
public Observable<Void> calculate() {
return observable.concatMap(o -> {
hasCalculated = true;
// returning Observable.just(null) makes the test pass
return Observable.empty();
});
}
}
}
I've tried to simplify the "bad" observable further, but can't find anything I can remove to make it simpler.
My current understanding, though, is that it's an Observable which (regardless of how it's constructed), should emit a single value and then complete. We then make two similar instances of an object based on that Observable, and call a method on those objects which consumes the Observable, makes a note of having done so, and then returns Observable.empty().
Can anyone explain why using this observable causes the test the fail (when using a simpler observable causes the test to pass)?
It's also possible to make the test pass by either serially calling calculate().toBlocking().subscribe() rather than using zip, or making calculate return Observable.just(null) instead. That makes some sense to me (zip won't subscribe to calc2 if calc1 is empty, since it in that case zip could never yield anything), but not complete sense (I don't understand why zip doesn't behave like that for a simpler version of badObservable - the calculate() methods still return empty, regardless of that input).

If you zip an empty source with something, the operator detects it can't produce any value anymore and unsubscribes from all of its sources. There is a mix of zip and merge involved and merge takes unsubscription seriously: it doesn't emit the value 3 at all thus concatMap doesn't call the mapping function for the second source either.

Related

How to chain vavr's Either nicely?

I have a function returning an Either<MyError, String> (function2) , which result depends on another function returning another Either<MyError, SomethingElse> (function1)
Both functions rely on a Try block that could fail, and I want to compose those two first function to create a "handle" which will be the main function of my class.
There are basically 3 scenarios possible :
function1 fails : I want handle to return the error given by function1
function1 succeeds and function2 fails : function2 must return its own error then returned by handle
both functions work : handle must return the String
Here is my current code :
private Either<MyError, Path> getPath(Arg arg) { // function 1
return Try.of(() -> //some code that can fail)
.toEither().mapLeft(e -> new MyError("Error message for function1", e));
}
private Either<MyError, String> getContent(Path path) { // function 2
return Try.of(() -> //some code that can fail)
.toEither().mapLeft(e -> new MyError("Error message for function2", e));
}
public Either<MyError, String> handle(Arg arg) {
return Either.right(arg)
.map(this::getPath)
.map(this::getContent);
}
Everything works except the Handle function, I think that my problem might be related to the use of Either::map function, that might not be the thing for my case.
Any thought about this ?
Also, sorry if the answer seems obvious, i am quite new to functionnal programming and vavr.
The method that could help to make this work would be flatMap.
So if you use flatMap instead of map, the handle method will become something like:
public Either<MyError, String> handle(Arg arg) {
return Either.<MyError, Arg>right(arg)
.flatMap(this::getPath)
.flatMap(this::getContent);
}
The scenarios you mentioned are all covered with this flatMap method.
See the Either.flatMap documentation for the official docs about it.

how to convert asynchronous promise code to rxjava

I have the following synchronous code that I would like to model as async code in RXJava.
void executeActions(List<Action> action) {
if (action == null || action.size() == 0) return;
for (Action action: actions) {
executeActions(action.handle());
}
}
class Action {
//implementation of handle
// return List<Action> or null.
List<Action> handle() {
}
}
Now in JS I can model this interaction with Promises like so. (Pseudo code below - my JS is weak)
executeActionsAsync(actions) {
var p = Promise.resolve();
action.forEach(function(action) {
p = p.then(function() {
action.handle();
})
}
return p;
}
class Action() {
function handle() {
actions = [];// some array of actions.
executeAsync(actions);
}
}
I would like to model the same in RXJava2. Any help is appreciated.
First of all, Sorry for my bad English.
I edited entire answer because I did not catch what his question is.
I don't know how implement of your Action class's handle function, However this function return value should change to RxJava2's async classes. In this case, Maybe class.
You wants how to implements recursion of async.
Handle List or null.
Use Maybe if you want to handle something or null. in RxJava2
class Action {
Maybe<List<Action>> handle() {}
}
This is what your Action class's handle returns.
void executeActions(Maybe<List<Action>> rxactions) {
// add null check.
// List<Action> handles as stream, but you can use for or iterator or whatever you want.
rxactions.subscribe(actions -> actions.stream().map(action -> executeActions(action.handle())));
}
Important thing is, handle() function returns properly.
Additional
In RxJava2, There are multiple classes to handle async.
Single, Flowable, Observable, Completable. And each classes instance method, subscribe.
Simply say,
1.Single => returns single class.
2.Flowable, Observable => returns multiple classes. (Flowable is more complex than Observable, which added back pressure.)
3.Completable => returns nothing, just succeed or not.
4.Maybe is returns * or null.
5.subscribe is execute this async.
:: Each classes can convert easily.
:: And There are so many ways to solve one problem. so it is just reference.
ex) Single<List<Foo>> <=> Flowable<Foo> // This is not same. but treat as similar.
PS.
I had this experience too. I think you need to learn more about RxJava2 to use properly everywhere.
Promise can devide into Single, Flowable, Observable, Completable. As describe above. This is the KEY to start understanding RxJava2.

Issue with using 'map' in RxJava 2 / RxAndroid 2

I'm trying to learn RXJAVA for Android. Parts make sense and I'm still confused about a lot of the other bits but, given some time I hope it will all make a lot more sense.
At present I'm having trouble with the 'map' functionality. I'm receiving an error but cannot quite figure out how to resolve it.
Before I share my code, I'll explain my understanding..
At a simple level..
Observable - Code that emits data.
Observer - Code that processes the emitted data.
Map - Code that takes in data of type A and returns it processed or as type B.
So, with this in mind:
In gradle I have:
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
If I have:
//declaration at top of file
private Observable<Integer> myIntObservable;
private Observer<Integer> myIntObserver;
private Observer<String> myStringObserver;
private Observable<String> myStringObservable;
//usage in a function
myIntObserver = new Observer<Integer>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Integer value) {
Toast.makeText(getApplicationContext(), "" + value, Toast.LENGTH_SHORT).show();
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
Toast.makeText(getApplicationContext(), "Int Observer Async Complete", Toast.LENGTH_SHORT).show();
}
};
//Connect my Observable to the observer.
myIntObservable.observeOn(Schedulers.io());
myIntObservable.subscribeOn(AndroidSchedulers.mainThread());
myIntObservable.subscribe(myIntObserver);
This all works fine... my map usage is similar..
What I would like to do is use this same observable that returns an int, then use the map code to instead return a string...
Therefore:
myStringObservable
.observeOn(Schedulers.io())
.subscribeOn(AndroidSchedulers.mainThread())
.map(new Function<Integer, String>() {
#Override
public String apply(Integer query){
return "String Observable result == " + query;
}
});
Now, I have two issues:
a) The build error I receive is:
Error:(179, 17) error: method map in class Observable cannot be applied to given types;
required: Function
found: >
reason: cannot infer type-variable(s) R
(argument mismatch; > cannot be converted to Function)
where R,T are type-variables:
R extends Object declared in method map(Function)
T extends Object declared in class Observable
I believe that this is essentially telling me that the types are not correct for my usage but, I can't clearly see... how to resolve this.
b) The map code that I have posted above doesn't connect the observable to what it needs to observe... hence, should I add the subscribe line before the map command?
Therefore, I tried this..
public void setupAsyncSubscription(){
myIntObservable
.observeOn(Schedulers.io())
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(myIntObserver)
.map(new Function<Integer, String>() {
#Override
public String apply(Integer query){
return "String Observable result == " + query;
}
});
}
Whilst this removes the error detailed in 'a' it instead provides me with the following error:
Error:(180, 17) error: void cannot be dereferenced (this points to the 'map' call)
Finally, I can also see that what I 'return' back from the 'map' function isn't being processed at all... I'm not clear how to process that. I feel that I should be using the .subscribe call in that case??
I 'think' that I am slowly on the right path to resolving the issue(s), but I'm not quite there and I don't want to just try and happen upon the answer without understanding what the problem is.
As always, any help is appreciated.
You have multiple issues here. There are - one by one:
//Connect my Observable to the observer.
myIntObservable.observeOn(Schedulers.io());
myIntObservable.subscribeOn(AndroidSchedulers.mainThread());
myIntObservable.subscribe(myIntObserver);
Code above would not work as you probably think.
Operators observeOn, subscribeOn are not designed to change internal observable state. They are returning new observable with desired behaviour.
To accomplish observing on io() thread and subscribing your observable on mainThread() you need to change the code:
//Connect my Observable to the observer.
myIntObservable = myIntObservable.observeOn(Schedulers.io());
myIntObservable = myIntObservable.subscribeOn(AndroidSchedulers.mainThread());
myIntObservable.subscribe(myIntObserver);
Or use (preferred) chaining:
//Connect my Observable to the observer.
myIntObservable
.observeOn(Schedulers.io());
.subscribeOn(AndroidSchedulers.mainThread());
.subscribe(myIntObserver);
For the code same as yours, calling .subscribe() on not changed Observable will result in subscribing and observing on the same thread from which you call .subscribe() (most likely from main thread).
Keep in mind you need to dispose observable once the work is finished.
When it comes to mapping problem - map() operator changes one type of Observable<A> into another type of observable Observable<B>.
If you'd like to end up with String objects converted from Integer objects you need to use - as a source of data - your original myIntObservable:
myStringObservable = myIntObservable
(...)
.map(new Function<Integer, String>() {
#Override
public String apply(Integer query){
return "String Observable result == " + query;
}
});
In above example myIntObservable will emit Integer objects (as expected in .apply(Integer query) method. Then .map() operator will create another Observable of type Observable<String> you can assign to myStringObservable (or do whatever you want from here).
Then, using myStringObservable you can subscribe to its events:
myStringObservable.subscribe(myStringObserver)
Again, please remember to dispose Observable when work is done.
Please also note that you should:
.observeOn() as soon as possible for current piece of work,
.subscribeOn() as late as possible (you don't want to continue io() or computation() operations on your main thread, right?).
Hint at the end: consider using lambdas with RxJava. Using all these anonymous classes (new Function() etc.) will make your code hard to read in the nearest future.
The first problem is that myStringObservable emits object of class String, but you're trying to map function which expects arguments of class Integer. In order to achieve what you want you should use myIntObservable.
The second problem is that subscribe call returns a Disposable object for you and you can't do map after that. Remove that subscribe call and this should be fine. Please also note that your method signature tells that it returns String but it can't return String, it can return Observable<String>.

Java 8 Stateful consumer

Is conditional composition of Consumers possible in Java 8? Basically I'm looking to create a custom Lambda interface similar to Consumer but that only works with one type of object. Let's call it, Stateful and it contains multiple statuses (we'll say two for the purpose of this example):
public class Stateful {
private int status1;
private int status2;
}
We have a lot of areas in our code where we do an operation on a Stateful and, if the status has changed, we would do another operation. I was wondering if we could use composition to handle this in a more compact and elegant manner. Right now we would do something like:
SimpleEntry<Integer, Integer> oldStates = new SimpleEntry(stateful.getStatus1(), stateful.getStatus2());
applyLogicOnStateful(stateful); //do some operation that may change state values
if(isStatusChanged(oldStates, stateful) { //compare oldStates integers to status integers
doSomethingElse(stateful);
}
where I think something like this would look better:
statefulConsumer
.accept((stateful)->applyLogicOnStateful(stateful))
.ifStatusChanged((stateful)->doSomethingElse(stateful));
but I don't know if we would be able to track the change in status from before the first consumer to after. Maybe I need to create a lambda that takes two consumers as input?
I'm definitely looking to do this without the assistance of a 3rd party library, although you're welcome to promote one here if it is helpful.
Here is a function that will return a Consumer<Stateful> that will extract the former state, do the change, compare results, and conditionally operate on the changed object.
public static Consumer<Stateful> getStatefulConsumer(
Function<Stateful,SimpleEntry<Integer,Integer>> getStatus, // extract status from Stateful
Consumer<Stateful> applyLogic, // apply business logic
BiPredicate<SimpleEntry<Integer,Integer>,SimpleEntry<Integer,Integer>> compareState, // test statuses for change
Consumer<Stateful> onChange) // doSomethingElse
{
return stateful -> {
SimpleEntry<Integer,Integer> oldStatus = getStatus.apply(stateful);
applyLogic.accept(stateful);
if(!compareState.test(oldStatus, getStatus.apply(stateful))){
onChange.accept(stateful);
}
};
}
You might use it like this:
Consumer<Stateful> ifChanged = getStatefulConsumer(s -> new SimpleEntry<> ( s.status1, s.status2 ),
s -> changeSomething(s), Objects::equals, s->doSomething(s));
You could generify the extracted status so that different stateful types could have different extracted status types, or even use Stateful::clone to copy the status.
The solution I am working with right now is to create a Lambda interface that takes the Stateful instance and two Consumers as input:
public interface StatefulConsumer {
void accept(Stateful stateful, Consumer<Stateful> consumer, Consumer<Stateful> ifStateChangedConsumer);
}
and an implementation:
final StatefulConsumer IfStateChanges = new StatefulConsumer() {
#Override
public void accept(Stateful stateful, Consumer<Stateful> consumer, Consumer<Stateful> ifStateChangedConsumer) {
SimpleEntry<Integer, Integer> oldStates = new SimpleEntry(stateful.getStatus1(), stateful.getStatus2());
consumer.accept(stateful); //do some operation that may change state values
if(isStatusChanged(oldStates, stateful) { //compare oldStates integers to status integers
ifStateChangedConsumer.accept(stateful);
}
}
};
which could be called like this:
IfStateChanges.accept(stateful,
(Stateful s)->applyLogicOnStateful(stateful),
(Stateful s)->doSomethingElse(stateful))
It could also be implemented as a Predicate or a Function that takes a stateful and a consumer as input and returns a boolean for use in an if Statement

RxJava: Find out if BehaviorSubject was a repeated value or not

I'm making an Android interface that shows some data fetched from the network. I want to have it show the latest available data, and to never be empty (unless no data has been fetched at all yet) so I'm using a BehaviorSubject to give subscribers (my UI) the latest available info, while refreshing it in the background to update it.
This works, but due to another requirement in my UI, I now have to know whether or not the published result was gotten fresh from the network or not. (In other words, I need to know if the published result was BehaviorSubject's saved item or not.)
How can I achieve this? If I need to split it up into multiple Observables, that's fine, as long as I'm able to get the caching behavior of BehaviorSubject (getting the last available result) while also being able to tell if the result returned was from the cache or not. A hacky way I can think of to do it would be to check if the timestamp of the response was relatively soon, but that'd be really sloppy and I'd rather figure out a way to do it with RxJava.
As you mentioned in the question, this can be accomplished with multiple Observables. In essence, you have two Observables: "the fresh response can be observed", and "the cached response can be observed". If something can be "observed", you can express it as an Observable. Let's name the first one original and the second replayed.
See this JSBin (JavaScript but the concepts can be directly translated to Java. There isn't a JavaBin as far as I know, for these purposes).
var original = Rx.Observable.interval(1000)
.map(function (x) { return {value: x, from: 'original'}; })
.take(4)
.publish().refCount();
var replayed = original
.map(function (x) { return {value: x.value, from: 'replayed'}; })
.replay(null, 1).refCount();
var merged = Rx.Observable.merge(original, replayed)
.replay(null, 1).refCount()
.distinctUntilChanged(function (obj) { return obj.value; });
console.log('subscribe 1st');
merged.subscribe(function (x) {
console.log('subscriber1: value ' + x.value + ', from: ' + x.from);
});
setTimeout(function () {
console.log(' subscribe 2nd');
merged.subscribe(function (x) {
console.log(' subscriber2: value ' + x.value + ', from: ' + x.from);
});
}, 2500);
The overall idea here is: annotate the event with a field from indicating its origin. If it's original, it's a fresh response. If it's replayed, it's a cached response. Observable original will only emit from: 'original' and Observable replayed will only emit from: 'replayed'. In Java we would require a bit more boilerplate because you need to make a class to represent these annotated events. Otherwise the same operators in RxJS can be found in RxJava.
The original Observable is publish().refCount() because we want only one instance of this stream, to be shared with all observers. In fact in RxJS and Rx.NET, share() is an alias for publish().refCount().
The replayed Observable is replay(1).refCount() because it is also shared just like the original one is, but replay(1) gives us the caching behavior.
merged Observable contains both original and replayed, and this is what you should expose to all subscribers. Since replayed will immediately emit whenever original does, we use distinctUntilChanged on the event's value to ignore immediate consecutives. The reason we replay(1).refCount() also the merged is because we want the merge of original and replay also to be one single shared instance of a stream shared among all observers. We would have used publish().refCount() for this purpose, but we cannot lose the replay effect that replayed contains, hence it's replay(1).refCount(), not publish().refCount().
Doesn't Distinct cover your case? BehaviorSubject only repeats the latest element after subscription.
I believe what you want is something like this:
private final BehaviorSubject<T> fetched = BehaviorSubject.create();
private final Observable<FirstTime<T>> _fetched = fetched.lift(new Observable.Operator<FirstTime<T>, T>() {
private AtomicReference<T> last = new AtomicReference<>();
#Override
public Subscriber<? super T> call(Subscriber<? super FirstTime<T>> child) {
return new Subscriber<T>(child) {
#Override
public void onCompleted() {
child.onCompleted();
}
#Override
public void onError(Throwable e) {
child.onError(e);
}
#Override
public void onNext(T t) {
if (!Objects.equals(t, last.getAndSet(t))) {
child.onNext(FirstTime.yes(t));
} else {
child.onNext(FirstTime.no(t));
}
}
};
}
});
public Observable<FirstTime<T>> getObservable() {
return _fetched;
}
public static class FirstTime<T> {
final boolean isItTheFirstTime;
final T value;
public FirstTime(boolean isItTheFirstTime, T value) {
this.isItTheFirstTime = isItTheFirstTime;
this.value = value;
}
public boolean isItTheFirstTime() {
return isItTheFirstTime;
}
public T getValue() {
return value;
}
public static <T> FirstTime<T> yes(T value) {
return new FirstTime<>(true, value);
}
public static <T> FirstTime<T> no(T value) {
return new FirstTime<>(false, value);
}
}
The wrapper class FirstTime has a boolean which can be used to see if any subscriber to the Observable has seen it before.
Hope that helps.
Store the information of BehaviorSubject objects in a data structure with a good lookup such as a Dictionnary. Each value would be a key and the value would be the number of iteration.
There so, when you look at a particulary key, if your dictionnary contains it already and its value is already at one, then you know that a value is a repeated value.
I'm not really sure what you want to achieve. Probably you'd just like to have a smart source for the "latest" data and a second source which tells you when the data was refreshed?
BehaviorSubject<Integer> dataSubject = BehaviorSubject.create(42); // initial value, "never empty"
Observable<String> refreshedIndicator = dataSubject.map(data -> "Refreshed!");
refreshedIndicator.subscribe(System.out::println);
Observable<Integer> latestActualData = dataSubject.distinctUntilChanged();
latestActualData.subscribe( data -> System.out.println( "Got new data: " + data));
// simulation of background activity:
Observable.interval(1, TimeUnit.SECONDS)
.limit(100)
.toBlocking()
.subscribe(aLong -> dataSubject.onNext(ThreadLocalRandom.current().nextInt(2)));
Output:
Refreshed!
Got new data: 42
Refreshed!
Got new data: 0
Refreshed!
Refreshed!
Refreshed!
Got new data: 1
Refreshed!
Got new data: 0
Refreshed!
Got new data: 1

Categories

Resources