package com.stanfy.enroscar.async.internal; import com.stanfy.enroscar.async.Async; import com.stanfy.enroscar.async.AsyncObserver; import rx.Observable; import rx.Subscriber; import rx.Subscription; /** * Adapts {@link rx.Observable} to {@link com.stanfy.enroscar.async.Async}. * @param <D> data type * @author Roman Mazur - Stanfy (http://stanfy.com) */ public abstract class ObservableAsyncProvider<D> implements AsyncProvider<D> { @Override public final Async<D> provideAsync() { return new RxAsync<>(provideObservable()); } protected abstract Observable<D> provideObservable(); /** * Adapter. Based on an assumption that methods of {@code Async} are invoked by {@code Loader} * in the main thread. * @param <D> data type */ private static class RxAsync<D> implements Async<D> { /** Observable. */ private final Observable<D> rxObservable; /** Cancellation flag. */ private boolean canceled; /** Current subscription. */ private Subscription subscription; private RxAsync(Observable<D> rxObservable) { this.rxObservable = rxObservable; } @Override public RxAsync<D> replicate() { return new RxAsync<>(rxObservable); } @Override public void subscribe(final AsyncObserver<D> observer) { if (canceled) { return; } subscription = rxObservable.subscribe(new Subscriber<D>() { @Override public void onCompleted() { if (!isUnsubscribed()) { observer.onReset(); } } @Override public void onError(final Throwable e) { // TODO: is it correct to emit errors if we are unsubscribed? observer.onError(e); } @Override public void onNext(final D d) { if (!isUnsubscribed()) { observer.onResult(d); } } }); } @Override public void cancel() { canceled = true; if (subscription != null) { subscription.unsubscribe(); subscription = null; } } } }