When creating an Observable like this:
public void foo() {
Observable observable = Observable.fromCallable(() -> {
bar();
return "";
})
.doOnSubscribe(disposable -> System.out.println("onSubscribe"))
.doOnDispose(() -> System.out.println("onDispose"));
Disposable disposable = observable.subscribe();
disposable.dispose();
}
private void bar() {
System.out.println("bar");
}
doOnSubcribe is called, doOnDispose is not called.
Why is that?
You need to use the doFinally() operator.
doOnDispose() has a very narrow use case, where the observable is explicitly disposed. In your example, the observable terminates "naturally" by onComplete(). By the time that you call dispose(), the observable is done, and nothing will happen -- disposing a completed observable has no effect.
Related
I have some workflow abstraction that relies on an interface WorkflowStep:
public interface WorkflowStep {
public void executeStep();
}
Now I have got three different classes that implement this interface:
GetCoordinatesForWaypoints, DisplayDetails, PlaySounds
My aim is to chain them with CompletableFuture, currently each overriden executeStep() method runs in a runnable, like shown here for example:
public class GetCoordinatesForEndpoints implements WorkflowStep {
#Override
public void executeStep() {
new Thread(new Runnable() {
#Override
public void run() {
//download coordinates from open street map
}).start();
}
}
The other classes methods look similiar. Now I have a central class where the workflow is started. Currently it looks like this:
public class DetailsDispatchWorkflow implements DispatchWorkflow {
private List<WorkflowStep> workflowSteps;
public DetailsDispatchWorkflow() {
workflowSteps = new LinkedList<>();
}
#Override
public void start() {
workflowSteps.add(new GetCoordinatesForEndpoints());
workflowSteps.add(new DisplayDetails());
workflowSteps.add(new PlaySounds());
workflowSteps.forEach(WorkflowStep::executeStep);
}
}
Now I want to replace this with CompletableFutures. The first thing I tried was to do something like this:
ExecutorService executorService = Executors.newFixedThreadPool(5);
CompletableFuture<WorkflowStep> workflowStepCompletableFuture =
CompletableFuture.supplyAsync(() -> new
GetCoordinatesForEndpoints().executeStep(), executorService);
which gives me an error (I think because the called method returns void). Calling only the constructor works. My next step is to chain those calls with thenAccept (because the called actions do not return a value), but that does not work either, when I append
.thenAccept(() -> new DisplayDetails().executeStep(), executorService);
I get an error that the compiler cannot infer the functional interface type. My quesiton is: How can I achieve the following call chain:
CompletableFuture<WorkflowStep> workflowStepCompletableFuture =
CompletableFuture
.supplyAsync(() -> new GetCoordinatesForEndpoints().executeStep(), executorService)
.thenAccept(() -> new DisplayDetails().executeStep(), executorService)
.thenAcceptAsync(() -> new PlaySounds().executeStep(), executorService);
when all instantiated objects implement the same interface?
Your WorkflowStep interface is basically equivalent to Runnable: no input, no output. In the CompletableFuture API, you should thus use the corresponding runAsync() and thenRunAsync() methods:
CompletableFuture<Void> workflowStepCompletableFuture =
CompletableFuture
.runAsync(() -> new GetCoordinatesForEndpoints().executeStep(), executorService)
.thenRunAsync(() -> new DisplayDetails().executeStep(), executorService)
.thenRunAsync(() -> new PlaySounds().executeStep(), executorService);
This will make all of them run asynchronously, but in sequence (as it seems you are trying to do).
Of course you should also remove the Thread creation from your implementation to make this useful.
Lets say I have a login and user data method, representing HTTP calls:
Single<LoginResponse> login();
Single<UserData> userData();
I need to call login() then userData(). If both succeed, the user is logged in.
I know how to wrap them up in a e.g. Completable:
Completable performLogin() {
login().doOnSuccess(this::storeLoginResponse)
.flatMap(userData())
.doOnSuccess(this::storeUserData)
.doOnError(this::wipeLoginData)
.toCompletable();
}
So the UI then says
showLoading();
performLogin().subscribe(() -> {
stopLoading();
onLoginSuccess();
}, error -> {
stopLoading();
onLoginFailure();
});
What if the UI needs to show which stage of the loading is happening? As in, when the login() call completes and the userData() call starts it will change the UI?
What I thought of is something like
Observable<LoginStage> performLogin() {
return Observable.create(emitter -> {
login.doOnSuccess(response -> {
storeLoginResponse(response)
emitter.onNext(LOGIN_COMPLETE)
}).flatMap(userData())
.subscribe(userData -> {
storeUserData(userData);
emitter.onNext(USER_DATA_COMPLETE)
emitter.onComplete();
}, error -> {
wipeLoginData();
emitter.onError(error);
});
});
}
But it feels like there's a nicer or more Rx-y way to do it.
You can use hot observables and chain one observable to another Subject and pass all items form one emission to another if you need it.
#Test
public void chainObservablesWithSubject() throws InterruptedException {
Observable<Long> observable = Observable.from(Arrays.asList(1l, 2l, 3l, 4l));
Subject<Long, Long> chainObservable = ReplaySubject.create(1);
observable.subscribe(chainObservable);
chainObservable.subscribe(System.out::println, (e) -> System.err.println(e.getMessage()), System.out::println);
}
You can check more examples here https://github.com/politrons/reactive/blob/master/src/test/java/rx/observables/connectable/HotObservable.java
I'm using Maybe class in RxJava2.
I registered the doOnDispose callback to detect the Dispose event, but it is not fired.
Maybe.just("aaa")
.doOnDispose({ /* do something */ })
.subscribe( ... )
I looked at the RxJava 2 code, but Maybe seemed not to support doOnDispose.
Maybe is create MaybePeek(not DoOnDisposeObserver) object in doOnDispose,,,
#CheckReturnValue
#SchedulerSupport("none")
public final Maybe<T> doOnDispose(Action onDispose) {
return RxJavaPlugins.onAssembly(new MaybePeek(this, Functions.emptyConsumer(), Functions.emptyConsumer(), Functions.emptyConsumer(), Functions.EMPTY_ACTION, Functions.EMPTY_ACTION, (Action)ObjectHelper.requireNonNull(onDispose, "onDispose is null")));
}
protected void subscribeActual(MaybeObserver<? super T> observer) {
this.source.subscribe(new MaybePeek.MaybePeekObserver(observer, this));
}
But, Single is create DoOnDisposeObserver, and it is worked fine.
#CheckReturnValue
#SchedulerSupport("none")
public final Single<T> doOnDispose(Action onDispose) {
ObjectHelper.requireNonNull(onDispose, "onDispose is null");
return RxJavaPlugins.onAssembly(new SingleDoOnDispose(this, onDispose));
}
protected void subscribeActual(SingleObserver<? super T> s) {
this.source.subscribe(new SingleDoOnDispose.DoOnDisposeObserver(s, this.onDispose));
}
Why Maybe.doOnDispose is not supported?
As the documentation says about doOnDispose(Action onDispose)
Calls the dispose Action if the downstream disposes the sequence.
Since your downstream never dispose it, it will never call.
Disposable disposable = Maybe.just("aaa")
.doOnDispose({ /* do something */ })
.subscribe( ... )
disposable.dispose();
Now the action in doOnDispose should be called.
Note that if the completion of the stream takes less time than the going to the next operation (disposable.dispose()), then the onDispose action should not be called. So, in order to verify it you can use a delay:
Disposable disposable = Maybe.just("aaa")
.delay(2000, TimeUnit.MILLISECONDS)
.doOnDispose({ /* do something */ })
.subscribe( ... )
disposable.dispose();
Now the action should be fired.
I have an observable that emits values. Based on these values I need to subscribe/unsubscribe to/from another Observable.
Is there a handy way of doing so? A convenient way instead creating a field for the subscription and handling it manually?
Example:
Observable A emits Booleans. If it emits true then a subscription should be made to Observable B - if false this subscription should be unsubscribed.
I'm not sure if we're 100% on the same page but I think you're missing one point. Maybe you'll think I'm nitpicking, but I think it will be good to get our terms straight.
Observable starts emitting values when a Subscriber subscribes to it. So unless you're thinking about two separate Subscribers you can't react to an emitted value with a subscription because the Observer won't emit anything.
That said... what (I think) you wanna do could be done this way:
Observable<Boolean> observableA = /* observable A initialization */;
final Observable<SomeObject> observableB = /* observable B initialization */;
observableA
.flatMap(new Func1<Boolean, Observable<SomeObject>>() {
#Override
public Observable<SomeObject> call(Boolean aBoolean) {
if (!aBoolean) {
throw new IllegalStateException("A dummy exception that is here just to cause the subscription to finish with error.");
}
return observableB;
}
})
.subscribe(
new Action1<SomeObject>() {
#Override
public void call(SomeObject someObject) {
// THIS IS A PART OF THE SUBSCRIBER TO OBSERVABLE B.
// THIS METHOD WILL BE CALLED ONLY IF THE OBSERVABLE A RETURNED TRUE
}
},
new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
// A dummy Action1 so the subscription does not crash on the Exception
}
});
If all of observables has the same type or you can combine whatever you want based on values.
Observable.from(new int[]{1,2,3,4,5})
.filter(i -> i < 5) // filter out something
.flatMap(i -> {
if (i < 2) { // subscribe on some observable, based on item value
return Observable.just(i);
} else {
return Observable.just(3);
}
})
I would need an Observable, for example to provide a system clock, which does not need to pass anything in onNext(). I couldn't find a signature that would allow me to do that.
Sure, I could use any object and then pass null, but that doesn't make much sense. So my question is if there is a better way to do that.
Observable.create(new Observable.OnSubscribe<Anyobject>() { // use any object in the signature
#Override public void call(Subscriber<? super Anyobject> subscriber) {
subscriber.onNext(null); // then pass null
subscriber.onCompleted();
}
})
You don't need to call onNext if your Observable doesn't emit anything.
You could use Void in your signature and do something like
Observable<Void> o = Observable.create(new Observable.OnSubscribe<Void>() {
#Override
public void call(Subscriber<? super Void> subscriber) {
// Do the work and call onCompleted when you done,
// no need to call onNext if you have nothing to emit
subscriber.onCompleted();
}
});
o.subscribe(new OnCompletedObserver<Void>() {
#Override
public void onCompleted() {
System.out.println("onCompleted");
}
#Override
public void onError(Throwable e) {
System.out.println("onError " + e.getMessage());
}
});
You can define an OnCompletedObserver to simplify your Observer callback so that you don't have to override the onNext since you don't need it.
public abstract class OnCompletedObserver<T> implements Observer<T> {
#Override
public void onNext(T o) {
}
}
If I've understood what you're asking then this should do the trick.
If you need something to be passed to onNext() before onCompleted() is called:
Observable.<Void>just(null)
If you only need onCompleted() to be called:
Observable.empty()
RxJava 2 Wiki:
RxJava 2.x no longer accepts null values and the following will yield
NullPointerException immediately or as a signal to downstream.
...
This means that Observable<Void> can no longer emit any values but
only terminate normally or with an exception. API designers may
instead choose to define Observable<Object> with no guarantee on what
Object will be (which should be irrelevant anyway)
It means that you can't use Void and do Observable.just(null).
Use Object or some other simple type instead:
Observable.just(new Object());
Starting with RxJava 2, the propper way to do this is to use a Completable
From the docs:
Represents a deferred computation without any value but only
indication for completion or exception. The class follows a similar
event pattern as Reactive-Streams: onSubscribe (onError|onComplete)?
One of the light solutions is to use Observable<Boolean>
And then onNext(Boolean.TRUE) which you then just ignore.
But probably you shouldn't use Observable in that case.
Consider using Completable instead
I don't know this will helps you or not.
The code written in RxSwift.
// Create an observable and emit somethings
let myObservable = Observable<Void>.create{ observer in
observer.on(.next(Void()))
return Disposables.create()
}
// Observer subscribe changes
myObservable.subscribe(onNext: {
_ in
print("Hello")
}).disposed(by: disposeBag)
Or use the Variable object
// Create a Variable object that contanins nothing
var myValueWatcher:Variable<Void> = Variable<Void>(Void())
// Observer subscribe changes
myValueWatcher.asObservable().skip(1).subscribe(onNext: {
_ in
print("Changes!")
}).disposed(by: disposeBag)
// The emit code
myValueWatcher.value = Void()