@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(); } }
@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 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 call(Subscriber<? super Long> op) { long l = 1; while (!op.isUnsubscribed()) { op.onNext(l++); } op.onCompleted(); }
@Override public void call() { 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 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); } }
private static void produceValuesAndAnError(Subscriber s) { Subscriber subscriber = (Subscriber) s; try { for (int ii = 0; ii < 50; ii++) { if (!subscriber.isUnsubscribed()) { subscriber.onNext("Pushed value " + ii); } if (ii == 5) { throw new Throwable("Something has gone wrong here"); } } if (!subscriber.isUnsubscribed()) { subscriber.onCompleted(); } } catch (Throwable throwable) { subscriber.onError(throwable); } }
@Test public void onErrorFailureWithUnsubscribeFailure() { Subscriber<String> o = OBSERVER_ONERROR_FAIL(); 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("onError failure")); fail("expects exception to be thrown"); } catch (Exception e) { e.printStackTrace(); assertTrue(o.isUnsubscribed()); // assertions for what is expected for the actual failure propagated to onError which then // fails assertTrue(e instanceof RuntimeException); assertEquals( "Error occurred when trying to propagate error to Observer.onError and during unsubscription.", e.getMessage()); Throwable e2 = e.getCause(); assertTrue(e2 instanceof CompositeException); assertEquals( "Chain of Causes for CompositeException In Order Received =>", e2.getCause().getMessage()); Throwable e3 = e2.getCause(); assertTrue(e3.getCause() instanceof SafeObserverTestException); assertEquals("onError failure", e3.getCause().getMessage()); Throwable e4 = e3.getCause(); assertTrue(e4.getCause() instanceof SafeObserverTestException); assertEquals("onErrorFail", e4.getCause().getMessage()); Throwable e5 = e4.getCause(); assertTrue(e5.getCause() instanceof SafeObserverTestException); assertEquals("failure from unsubscribe", e5.getCause().getMessage()); } }
private void init() { // AndroidRx 再探 File[] folders = new File[5]; Observable.from(folders) .flatMap( new Func1<File, Observable<File>>() { @Override public Observable<File> call(File file) { return Observable.from(file.listFiles()); } }) .filter( new Func1<File, Boolean>() { @Override public Boolean call(File file) { return file.getName().endsWith(".png"); } }) .map( new Func1<File, Bitmap>() { @Override public Bitmap call(File file) { return getBitmapFromFile(file); } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( new Action1<Bitmap>() { @Override public void call(Bitmap bitmap) { // 主线程处理 } }); Observer<String> observer = new Observer<String>() { @Override public void onCompleted() {} @Override public void onError(Throwable e) {} @Override public void onNext(String s) {} }; // Observer 扩展类 Subscriber // 区别 onStart() Subscriber<String> subscriber = new Subscriber<String>() { @Override public void onStart() { super.onStart(); } @Override public void onCompleted() {} @Override public void onError(Throwable e) {} @Override public void onNext(String s) {} }; subscriber.isUnsubscribed(); // 是否取消订阅 subscriber.unsubscribe(); // 取消订阅 Observable<String> observable = Observable.create( new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onStart(); subscriber.onNext("Hello"); subscriber.onNext("Hi"); subscriber.onCompleted(); } }); observable.subscribe(observer); // 订阅 observable.subscribe(subscriber); // 同上,类似监听点击事件 // 应用一: Observable.just(0, 1, 2, 3) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( new Action1<Integer>() { @Override public void call(Integer integer) { LogUtil.d(String.valueOf(integer)); } }); // 应用二: Observable.just(0) .map( new Func1<Integer, Drawable>() { @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public Drawable call(Integer integer) { return getTheme().getDrawable(integer); } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( new Observer<Drawable>() { @Override public void onCompleted() {} @Override public void onError(Throwable e) { ToastManager.show(getBaseContext(), e.getMessage()); } @Override public void onNext(Drawable drawable) { // TODO 显示内容 } }); RxView.clickEvents(null) .throttleFirst(500, TimeUnit.MILLISECONDS) // 防抖动 .subscribe( new Action1<ViewClickEvent>() { @Override public void call(ViewClickEvent viewClickEvent) {} }); }
void emitLoop() { final Subscriber<? super T> c = child; outer: for (; ; ) { long localRequested; Producer localProducer; Object localTerminal; List<T> q; synchronized (this) { localRequested = missedRequested; localProducer = missedProducer; localTerminal = missedTerminal; q = queue; if (localRequested == 0L && localProducer == null && q == null && localTerminal == null) { emitting = false; return; } missedRequested = 0L; missedProducer = null; queue = null; missedTerminal = null; } boolean empty = q == null || q.isEmpty(); if (localTerminal != null) { if (localTerminal != Boolean.TRUE) { c.onError((Throwable) localTerminal); return; } else if (empty) { c.onCompleted(); return; } } long e = 0; if (q != null) { for (T v : q) { if (c.isUnsubscribed()) { return; } else if (hasError) { continue outer; // if an error has been set, shortcut the loop and act on it } try { c.onNext(v); } catch (Throwable ex) { Exceptions.throwOrReport(ex, c, v); return; } } e += q.size(); } long r = requested; // if requested is max, we don't do any accounting if (r != Long.MAX_VALUE) { // if there were missing requested, add it up if (localRequested != 0L) { long u = r + localRequested; if (u < 0) { u = Long.MAX_VALUE; } r = u; } // if there were emissions and we don't run on max since the last check, subtract if (e != 0L && r != Long.MAX_VALUE) { long u = r - e; if (u < 0) { throw new IllegalStateException("More produced than requested"); } r = u; } requested = r; } if (localProducer != null) { if (localProducer == NULL_PRODUCER) { currentProducer = null; } else { currentProducer = localProducer; if (r != 0L) { localProducer.request(r); } } } else { Producer p = currentProducer; if (p != null && localRequested != 0L) { p.request(localRequested); } } } }
protected void drain() { synchronized (this) { if (emitting) { missedEmitting++; return; } emitting = true; missedEmitting = 0; } final List<SourceSubscriber<T>.MergeItemSubscriber> subs = subscribers; final Subscriber<T> child = s; Object[] active = new Object[subs.size()]; do { long r; outer: while ((r = requested) > 0) { int idx = lastIndex; synchronized (subs) { if (subs.size() == active.length) { active = subs.toArray(active); } else { active = subs.toArray(); } } int resumeIndex = 0; int j = 0; for (Object o : active) { @SuppressWarnings("unchecked") MergeItemSubscriber e = (MergeItemSubscriber) o; if (e.index == idx) { resumeIndex = j; break; } j++; } int sumConsumed = 0; for (int i = 0; i < active.length; i++) { j = (i + resumeIndex) % active.length; @SuppressWarnings("unchecked") final MergeItemSubscriber e = (MergeItemSubscriber) active[j]; final RxRingBuffer b = e.buffer; lastIndex = e.index; if (!e.once && b.peek() == null) { subs.remove(e); synchronized (guard) { this.active--; } csub.remove(e); e.release(); subscribeNext(); WIP.decrementAndGet(this); continue outer; } int consumed = 0; Object v; while (r > 0 && (v = b.poll()) != null) { nl.accept(child, v); if (child.isUnsubscribed()) { return; } r--; consumed++; } if (consumed > 0) { sumConsumed += consumed; REQUESTED.addAndGet(this, -consumed); e.requestMore(consumed); } if (r == 0) { break outer; } } if (sumConsumed == 0) { break; } } if (active.length == 0) { if (wip == 0) { child.onCompleted(); return; } } synchronized (this) { if (missedEmitting == 0) { emitting = false; break; } missedEmitting = 0; } } while (true); }