@Test public void onCompleteSuccessWithUnsubscribeFailure() { Subscriber<String> o = OBSERVER_SUCCESS(); try { o.add( Subscriptions.create( new Action0() { @Override public void call() { // break contract by throwing exception throw new SafeObserverTestException("failure from unsubscribe"); } })); new SafeSubscriber<String>(o).onCompleted(); fail("expects exception to be thrown"); } catch (Exception e) { e.printStackTrace(); assertTrue(o.isUnsubscribed()); assertTrue(e instanceof SafeObserverTestException); assertEquals("failure from unsubscribe", e.getMessage()); // expected since onError fails so SafeObserver can't help } }
@Override public void request(long n) { if (once) { return; } if (n < 0L) { throw new IllegalStateException("n >= required but it was " + n); } if (n != 0L) { once = true; Subscriber<? super T> a = actual; if (a.isUnsubscribed()) { return; } T v = value; try { a.onNext(v); } catch (Throwable e) { Exceptions.throwOrReport(e, a, v); return; } if (a.isUnsubscribed()) { return; } a.onCompleted(); } }
@Override public void call(final Subscriber<? super T> s) { if (state.casFirst(0, 1)) { final NotificationLite<T> nl = NotificationLite.instance(); // drain queued notifications before subscription // we do this here before PassThruObserver so the consuming thread can do this before // putting itself in the line of the producer BufferedObserver<? super T> buffered = (BufferedObserver<? super T>) state.observerRef; Object o; while ((o = buffered.buffer.poll()) != null) { nl.accept(s, o); } // register real observer for pass-thru ... and drain any further events received on first // notification state.setObserverRef(new PassThruObserver<T>(s, buffered.buffer, state)); s.add( Subscriptions.create( new Action0() { @Override public void call() { state.setObserverRef(Subscribers.empty()); } })); } else { s.onError(new IllegalStateException("Only one subscriber allowed!")); } }
@Override public void unsubscribe() { errorSubscriber.unsubscribe(); stateSubscriber.unsubscribe(); indexSubscriber.unsubscribe(); commandSubscriber.unsubscribe(); }
@Test public void testAlreadyUnsubscribedInterleavesWithClient() { ReplaySubject<Integer> source = ReplaySubject.create(); Subscriber<Integer> done = Subscribers.empty(); done.unsubscribe(); @SuppressWarnings("unchecked") Observer<Integer> o = mock(Observer.class); InOrder inOrder = inOrder(o); Observable<Integer> result = source.publish().refCount(); result.subscribe(o); source.onNext(1); result.subscribe(done); source.onNext(2); source.onCompleted(); inOrder.verify(o).onNext(1); inOrder.verify(o).onNext(2); inOrder.verify(o).onCompleted(); verify(o, never()).onError(any(Throwable.class)); }
@Test public void onErrorSuccessWithUnsubscribeFailure() { AtomicReference<Throwable> onError = new AtomicReference<Throwable>(); Subscriber<String> o = OBSERVER_SUCCESS(onError); try { o.add( Subscriptions.create( new Action0() { @Override public void call() { // break contract by throwing exception throw new SafeObserverTestException("failure from unsubscribe"); } })); new SafeSubscriber<String>(o).onError(new SafeObserverTestException("failed")); fail("we expect the unsubscribe failure to cause an exception to be thrown"); } catch (Exception e) { e.printStackTrace(); assertTrue(o.isUnsubscribed()); // we still expect onError to have received something before unsubscribe blew up assertNotNull(onError.get()); assertTrue(onError.get() instanceof SafeObserverTestException); assertEquals("failed", onError.get().getMessage()); // now assert the exception that was thrown assertTrue(e instanceof SafeObserverTestException); assertEquals("failure from unsubscribe", e.getMessage()); } }
@Test public void testUnsubscribeAfterTake() { final Subscription s = mock(Subscription.class); TestObservableFunc f = new TestObservableFunc("one", "two", "three"); Observable<String> w = Observable.create(f); @SuppressWarnings("unchecked") Observer<String> observer = mock(Observer.class); Subscriber<String> subscriber = Subscribers.from(observer); subscriber.add(s); Observable<String> take = w.lift(new OperatorTake<String>(1)); take.subscribe(subscriber); // wait for the Observable to complete try { f.t.join(); } catch (Throwable e) { e.printStackTrace(); fail(e.getMessage()); } System.out.println("TestObservable thread finished"); verify(observer, times(1)).onNext("one"); verify(observer, never()).onNext("two"); verify(observer, never()).onNext("three"); verify(observer, times(1)).onCompleted(); verify(s, times(1)).unsubscribe(); verifyNoMoreInteractions(observer); }
@Override public void run() { System.out.println("Doing something expensive"); reactiveXBoilerplate.sleep(3000); subscriber.onNext("Expensive result"); subscriber.onCompleted(); }
@Override public void onError(Throwable e) { long p = produced; if (p != 0L) { arbiter.produced(p); } Observable<T> o; try { o = onError.call(e); } catch (Throwable ex) { Exceptions.throwIfFatal(ex); actual.onError(new CompositeException(e, ex)); return; } if (o == null) { actual.onError( new NullPointerException("The onError function returned a null Observable.")); } else { o.unsafeSubscribe(new ResumeSubscriber<T>(actual, arbiter)); } }
@Override public void call(Subscriber<? super Long> op) { long l = 1; while (!op.isUnsubscribed()) { op.onNext(l++); } op.onCompleted(); }
@Override public Subscriber<? super T> call(final Subscriber<? super Map<K, V>> subscriber) { Map<K, V> localMap; try { localMap = mapFactory.call(); } catch (Throwable ex) { Exceptions.throwIfFatal(ex); subscriber.onError(ex); Subscriber<? super T> parent = Subscribers.empty(); parent.unsubscribe(); return parent; } final Map<K, V> fLocalMap = localMap; return new Subscriber<T>(subscriber) { private Map<K, V> map = fLocalMap; @Override public void onStart() { request(Long.MAX_VALUE); } @Override public void onNext(T v) { K key; V value; try { key = keySelector.call(v); value = valueSelector.call(v); } catch (Throwable ex) { Exceptions.throwIfFatal(ex); subscriber.onError(ex); return; } map.put(key, value); } @Override public void onError(Throwable e) { map = null; subscriber.onError(e); } @Override public void onCompleted() { Map<K, V> map0 = map; map = null; subscriber.onNext(map0); subscriber.onCompleted(); } }; }
@Override public void onViewDetachedFromWindow(View v) { if (!isUnsubscribed()) { Subscriber<? super View> originalSubscriber = subscriber; unsubscribe(); originalSubscriber.onNext(v); originalSubscriber.onCompleted(); } }
private void onWifiEnabled() { Log.d("WifiService", "The Wifi has been enabled."); unregisterReceiver(wifiStateChangedReceiver); wifiStateChangedReceiver = null; while (!wifiStateChangedSubscribers.isEmpty()) { Subscriber subscriber = wifiStateChangedSubscribers.poll(); subscriber.onCompleted(); } }
@Test public void testRequestFromDecoupledOperatorThatRequestsN() { Subscriber<String> s = new TestSubscriber<String>(); final AtomicLong innerR = new AtomicLong(); Operator<String, String> o = new Operator<String, String>() { @Override public Subscriber<? super String> call(Subscriber<? super String> child) { // we want to decouple the chain so set our own Producer on the child instead of it // coming from the parent child.setProducer( new Producer() { @Override public void request(long n) { innerR.set(n); } }); Subscriber<String> as = new Subscriber<String>() { @Override public void onCompleted() {} @Override public void onError(Throwable e) {} @Override public void onNext(String t) {} }; // we request 99 up to the parent as.request(99); return as; } }; s.request(10); Subscriber<? super String> ns = o.call(s); final AtomicLong r = new AtomicLong(); // set set the producer at the top of the chain (ns) and it should flow through the operator to // the (s) subscriber // and then it should request up with the value set on the final Subscriber (s) ns.setProducer( new Producer() { @Override public void request(long n) { r.set(n); } }); assertEquals(99, r.get()); assertEquals(10, innerR.get()); }
@Override public Subscriber<? super Observable<? extends T>> call(Subscriber<? super T> child) { final SerializedSubscriber<T> s = new SerializedSubscriber<T>(child); final CompositeSubscription csub = new CompositeSubscription(); child.add(csub); SourceSubscriber<T> ssub = new SourceSubscriber<T>(maxConcurrency, s, csub); child.setProducer(new MergeMaxConcurrentProducer<T>(ssub)); return ssub; }
@Override public void onPreviewFrame(byte[] data) { if (subscriber != null && !subscriber.isUnsubscribed() && rxCamera.isOpenCamera()) { if (data == null || data.length == 0) { subscriber.onError(new CameraDataNullException()); } RxCameraData rxCameraData = new RxCameraData(); rxCameraData.cameraData = data; rxCameraData.rotateMatrix = rxCamera.getRotateMatrix(); subscriber.onNext(rxCameraData); } }
/** Should request -1 for infinite */ @Test public void testRequestFromFinalSubscribeWithoutRequestValue() { Subscriber<String> s = new TestSubscriber<String>(); final AtomicLong r = new AtomicLong(); s.setProducer( new Producer() { @Override public void request(long n) { r.set(n); } }); assertEquals(Long.MAX_VALUE, r.get()); }
@Override public Subscriber<? super T> call(final Subscriber<? super T> child) { final ParentSubscriber parent = new ParentSubscriber(child); child.add(parent); // don't unsubscribe downstream child.setProducer( new Producer() { @Override public void request(long n) { parent.downstreamRequest(n); } }); return parent; }
private void triggerServiceActive() { try { Iterator localIterator = this.networkSubscribers.iterator(); while (localIterator.hasNext()) { Subscriber localSubscriber = (Subscriber)localIterator.next(); localSubscriber.onNext(this.mNetworkManager); localSubscriber.onCompleted(); localIterator.remove(); } } finally {} }
@Override public void call(final Subscriber<? super Bitmap> subscriber) { Preconditions.checkUiThread(); final Target target = new TargetAdapter() { @Override public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { if (!subscriber.isUnsubscribed()) subscriber.onNext(bitmap); } @Override public void onBitmapFailed(Drawable errorDrawable) { if (!subscriber.isUnsubscribed()) subscriber.onError(new PicassoError(errorDrawable)); } }; Picasso.with(context) .load(resId) .noFade() .memoryPolicy(NO_CACHE, NO_STORE) .config(Bitmap.Config.ARGB_8888) .transform(new PicassoTransformation(context, radius)) .into(target); subscriber.add( new MainThreadSubscription() { @Override protected void onUnsubscribe() { Picasso.with(context).cancelRequest(target); PicassoBlurOnSubscribe.this.context = null; } }); }
@Override public void call(final Subscriber<? super Void> subscriber) { checkUiThread(); SearchEditText.OnKeyboardDismissListener listener = new SearchEditText.OnKeyboardDismissListener() { @Override public void onKeyboardDismiss() { if (!subscriber.isUnsubscribed()) { subscriber.onNext(null); } } }; view.setOnKeyboardDismissListener(listener); subscriber.add( new MainThreadSubscription() { @Override protected void onUnsubscribe() { // TODO: set to null once http://b.android.com/187101 is released. view.setOnKeyboardDismissListener( new SearchEditText.OnKeyboardDismissListener() { @Override public void onKeyboardDismiss() {} }); } }); }
@Override public void call(final Subscriber<? super MotionEvent> subscriber) { checkUiThread(); View.OnTouchListener listener = new View.OnTouchListener() { @Override public boolean onTouch(View v, @NonNull MotionEvent event) { if (handled.call(event)) { if (!subscriber.isUnsubscribed()) { subscriber.onNext(event); } return true; } return false; } }; view.setOnTouchListener(listener); subscriber.add( new MainThreadSubscription() { @Override protected void onUnsubscribe() { view.setOnTouchListener(null); } }); }
@Override public void call(final Subscriber<? super RecyclerViewChildAttachStateChangeEvent> subscriber) { checkUiThread(); final OnChildAttachStateChangeListener listener = new OnChildAttachStateChangeListener() { @Override public void onChildViewAttachedToWindow(View childView) { if (!subscriber.isUnsubscribed()) { subscriber.onNext(RecyclerViewChildAttachEvent.create(recyclerView, childView)); } } @Override public void onChildViewDetachedFromWindow(View childView) { if (!subscriber.isUnsubscribed()) { subscriber.onNext(RecyclerViewChildDetachEvent.create(recyclerView, childView)); } } }; recyclerView.addOnChildAttachStateChangeListener(listener); subscriber.add( new MainThreadSubscription() { @Override protected void onUnsubscribe() { recyclerView.removeOnChildAttachStateChangeListener(listener); } }); }
/** * @warn javadoc description missing * @warn param producer not described * @param producer */ public void setProducer(Producer producer) { long toRequest; boolean setProducer = false; synchronized (this) { toRequest = requested; p = producer; if (op != null) { // middle operator ... we pass thru unless a request has been made if (toRequest == Long.MIN_VALUE) { // we pass-thru to the next producer as nothing has been requested setProducer = true; } } } // do after releasing lock if (setProducer) { op.setProducer(p); } else { // we execute the request with whatever has been requested (or Long.MAX_VALUE) if (toRequest == Long.MIN_VALUE) { p.request(Long.MAX_VALUE); } else { p.request(toRequest); } } }
@Override public void call(final Subscriber<? super FileEvent> subscriber) { final FileObserver observer = new FileObserver(pathToWatch) { @Override public void onEvent(int event, String file) { if (subscriber.isUnsubscribed()) { return; } FileEvent fileEvent = FileEvent.create(event, file); subscriber.onNext(fileEvent); if (fileEvent.isDeleteSelf()) { subscriber.onCompleted(); } } }; observer.startWatching(); // START OBSERVING subscriber.add( Subscriptions.create( new Action0() { @Override public void call() { observer.stopWatching(); } })); }
@Override public void call(final Subscriber<? super Void> subscriber) { verifyMainThread(); final ViewTreeObserver.OnPreDrawListener listener = new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { if (!subscriber.isUnsubscribed()) { subscriber.onNext(null); return proceedDrawingPass.call(); } return true; } }; view.getViewTreeObserver().addOnPreDrawListener(listener); subscriber.add( new MainThreadSubscription() { @Override protected void onUnsubscribe() { view.getViewTreeObserver().removeOnPreDrawListener(listener); } }); }
@Override public void call(final Subscriber<? super MenuItem> subscriber) { verifyMainThread(); PopupMenu.OnMenuItemClickListener listener = new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { if (!subscriber.isUnsubscribed()) { subscriber.onNext(item); } return true; } }; view.setOnMenuItemClickListener(listener); subscriber.add( new MainThreadSubscription() { @Override protected void onUnsubscribe() { view.setOnMenuItemClickListener(null); } }); }
SwitchSubscriber(Subscriber<? super T> child) { serializedChild = new SerializedSubscriber<T>(child); arbiter = new ProducerArbiter(); ssub = new SerialSubscription(); child.add(ssub); child.setProducer( new Producer() { @Override public void request(long n) { if (n > 0) { arbiter.request(n); } } }); }
@Override public void call(final Subscriber<? super View> subscriber) { verifyMainThread(); SwipeDismissBehavior.OnDismissListener listener = new SwipeDismissBehavior.OnDismissListener() { @Override public void onDismiss(View view) { if (!subscriber.isUnsubscribed()) { subscriber.onNext(view); } } @Override public void onDragStateChanged(int i) {} }; if (!(view.getLayoutParams() instanceof LayoutParams)) { throw new IllegalArgumentException("The view is not in a Coordinator Layout."); } LayoutParams params = (LayoutParams) view.getLayoutParams(); final SwipeDismissBehavior behavior = (SwipeDismissBehavior) params.getBehavior(); if (behavior == null) { throw new IllegalStateException("There's no behavior set on this view."); } behavior.setListener(listener); subscriber.add( new MainThreadSubscription() { @Override protected void onUnsubscribe() { behavior.setListener(null); } }); }
@Override public void onNext(T t) { synchronized (this) { if (emitting) { List<T> q = queue; if (q == null) { q = new ArrayList<T>(4); queue = q; } q.add(t); return; } } boolean skipFinal = false; try { child.onNext(t); long r = requested; if (r != Long.MAX_VALUE) { requested = r - 1; } emitLoop(); skipFinal = true; } finally { if (!skipFinal) { synchronized (this) { emitting = false; } } } }