rx.operators.OperationDelay Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rxjava-core Show documentation
Show all versions of rxjava-core Show documentation
rxjava-core developed by Netflix
/**
* Copyright 2014 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package rx.operators;
import java.util.concurrent.TimeUnit;
import rx.Observable;
import rx.Observable.OnSubscribeFunc;
import rx.Observer;
import rx.Scheduler;
import rx.Scheduler.Inner;
import rx.Subscription;
import rx.functions.Action1;
import rx.functions.Func0;
import rx.functions.Func1;
import rx.observables.ConnectableObservable;
import rx.subscriptions.CompositeSubscription;
import rx.subscriptions.SerialSubscription;
import rx.subscriptions.Subscriptions;
public final class OperationDelay {
public static Observable delay(Observable observable, final long delay, final TimeUnit unit, final Scheduler scheduler) {
// observable.map(x => Observable.timer(t).map(_ => x).startItAlreadyNow()).concat()
Observable> seqs = observable.map(new Func1>() {
public Observable call(final T x) {
ConnectableObservable co = Observable.timer(delay, unit, scheduler).map(new Func1() {
@Override
public T call(Long ignored) {
return x;
}
}).replay();
co.connect();
return co;
}
});
return Observable.concat(seqs);
}
/**
* Delays the subscription to the source by the given amount, running on the given scheduler.
*/
public static OnSubscribeFunc delaySubscription(Observable extends T> source, long time, TimeUnit unit, Scheduler scheduler) {
return new DelaySubscribeFunc(source, time, unit, scheduler);
}
/** Subscribe function which schedules the actual subscription to source on a scheduler at a later time. */
private static final class DelaySubscribeFunc implements OnSubscribeFunc {
final Observable extends T> source;
final Scheduler scheduler;
final long time;
final TimeUnit unit;
public DelaySubscribeFunc(Observable extends T> source, long time, TimeUnit unit, Scheduler scheduler) {
this.source = source;
this.scheduler = scheduler;
this.time = time;
this.unit = unit;
}
@Override
public Subscription onSubscribe(final Observer super T> t1) {
final SerialSubscription ssub = new SerialSubscription();
ssub.set(scheduler.schedule(new Action1() {
@Override
public void call(Inner inner) {
if (!ssub.isUnsubscribed()) {
ssub.set(source.subscribe(t1));
}
}
}, time, unit));
return ssub;
}
}
/**
* Delay the emission of the source items by a per-item observable that fires its first element.
*/
public static OnSubscribeFunc delay(Observable extends T> source,
Func1 super T, ? extends Observable> itemDelay) {
return new DelayViaObservable(source, null, itemDelay);
}
/**
* Delay the subscription and emission of the source items by a per-item observable that fires its first element.
*/
public static OnSubscribeFunc delay(Observable extends T> source,
Func0 extends Observable> subscriptionDelay,
Func1 super T, ? extends Observable> itemDelay) {
return new DelayViaObservable(source, subscriptionDelay, itemDelay);
}
/**
* Delay the emission of the source items by a per-item observable that fires its first element.
*/
private static final class DelayViaObservable implements OnSubscribeFunc {
final Observable extends T> source;
final Func0 extends Observable> subscriptionDelay;
final Func1 super T, ? extends Observable> itemDelay;
public DelayViaObservable(Observable extends T> source,
Func0 extends Observable> subscriptionDelay,
Func1 super T, ? extends Observable> itemDelay) {
this.source = source;
this.subscriptionDelay = subscriptionDelay;
this.itemDelay = itemDelay;
}
@Override
public Subscription onSubscribe(Observer super T> t1) {
CompositeSubscription csub = new CompositeSubscription();
SerialSubscription sosub = new SerialSubscription();
csub.add(sosub);
SourceObserver so = new SourceObserver(t1, itemDelay, csub, sosub);
if (subscriptionDelay == null) {
sosub.set(source.subscribe(so));
} else {
Observable subscriptionSource;
try {
subscriptionSource = subscriptionDelay.call();
} catch (Throwable t) {
t1.onError(t);
return Subscriptions.empty();
}
SerialSubscription ssub = new SerialSubscription();
csub.add(ssub);
ssub.set(subscriptionSource.subscribe(new SubscribeDelay(source, so, csub, ssub)));
}
return csub;
}
/** Subscribe delay observer. */
private static final class SubscribeDelay implements Observer {
final Observable extends T> source;
final SourceObserver so;
final CompositeSubscription csub;
final Subscription self;
/** Prevent any onError once the first item was delivered. */
boolean subscribed;
public SubscribeDelay(
Observable extends T> source,
SourceObserver so,
CompositeSubscription csub, Subscription self) {
this.source = source;
this.so = so;
this.csub = csub;
this.self = self;
}
@Override
public void onNext(U args) {
onCompleted();
}
@Override
public void onError(Throwable e) {
if (!subscribed) {
so.observer.onError(e);
csub.unsubscribe();
}
}
@Override
public void onCompleted() {
subscribed = true;
csub.remove(self);
so.self.set(source.subscribe(so));
}
}
/** The source observer. */
private static final class SourceObserver implements Observer {
final Observer super T> observer;
final Func1 super T, ? extends Observable> itemDelay;
final CompositeSubscription csub;
final SerialSubscription self;
/** Guard to avoid overlapping events from the various sources. */
final Object guard;
boolean done;
int wip;
public SourceObserver(Observer super T> observer,
Func1 super T, ? extends Observable> itemDelay,
CompositeSubscription csub,
SerialSubscription self) {
this.observer = observer;
this.itemDelay = itemDelay;
this.csub = csub;
this.guard = new Object();
this.self = self;
}
@Override
public void onNext(T args) {
Observable delayer;
try {
delayer = itemDelay.call(args);
} catch (Throwable t) {
onError(t);
return;
}
synchronized (guard) {
wip++;
}
SerialSubscription ssub = new SerialSubscription();
csub.add(ssub);
ssub.set(delayer.subscribe(new DelayObserver(args, this, ssub)));
}
@Override
public void onError(Throwable e) {
synchronized (guard) {
observer.onError(e);
}
csub.unsubscribe();
}
@Override
public void onCompleted() {
boolean b;
synchronized (guard) {
done = true;
b = checkDone();
}
if (b) {
csub.unsubscribe();
} else {
self.unsubscribe();
}
}
void emit(T value, Subscription token) {
boolean b;
synchronized (guard) {
observer.onNext(value);
wip--;
b = checkDone();
}
if (b) {
csub.unsubscribe();
} else {
csub.remove(token);
}
}
boolean checkDone() {
if (done && wip == 0) {
observer.onCompleted();
return true;
}
return false;
}
}
/**
* Delay observer.
*/
private static final class DelayObserver implements Observer {
final T value;
final SourceObserver parent;
final Subscription token;
public DelayObserver(T value, SourceObserver parent, Subscription token) {
this.value = value;
this.parent = parent;
this.token = token;
}
@Override
public void onNext(U args) {
parent.emit(value, token);
}
@Override
public void onError(Throwable e) {
parent.onError(e);
}
@Override
public void onCompleted() {
parent.emit(value, token);
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy