preface
Rxjava can easily switch threads, so how does rxjava switch threads? Read this article to learn how rxjava performs thread switching and the impact of thread switching.
A simple code:
Observable.create(new ObservableOnSubscribe<String>() { @Override public void subscribe(ObservableEmitter<String> e) throws Exception { Log.d("WanRxjava ", "subscrib td ==" + Thread.currentThread().getName()); e.onNext("I'm sending next"); e.onComplete(); } }).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<String>() { @Override public void onSubscribe(Disposable d) { Log.d("WanRxjava ", "onSubscribe td ==" + Thread.currentThread().getName()); } @Override public void onNext(String value) { Log.d("WanRxjava ", "onNext td ==" + Thread.currentThread().getName()); } @Override public void onError(Throwable e) { } @Override public void onComplete() { Log.d("WanRxjava ", "onComplete td ==" + Thread.currentThread().getName()); } });
The above code implements the logic of thread switching and binding the observer to the observed. Let's look at the above code logic in four parts: create, subscribeOn, observeOn and subscribe
1.create
As the name suggests, create is to create an observer. Here, a parameter is ObservableOnSubscribe, which is an interface class. Let's look at the source code of create:
@SchedulerSupport(SchedulerSupport.NONE) public static <T> Observable<T> create(ObservableOnSubscribe<T> source) { ObjectHelper.requireNonNull(source, "source is null"); return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source)); }
After the ObservableOnSubscribe is passed in, new ObservableCreate(source) is called
public final class ObservableCreate<T> extends Observable<T> { final ObservableOnSubscribe<T> source; public ObservableCreate(ObservableOnSubscribe<T> source) { this.source = source; } }
One variable of ObservableCreate is source. Here, we just assign the incoming ObservableOnSubscribe to source, that is, make a layer of packaging, and then return.
2.subscribeOn
After calling create, it returns ObservableCreate (Observable), and then continues to call subscribeOn, passing in a variable Schedulers.io()
@SchedulerSupport(SchedulerSupport.CUSTOM) public final Observable<T> subscribeOn(Scheduler scheduler) { ObjectHelper.requireNonNull(scheduler, "scheduler is null"); return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler)); }
We see that new ObservableSubscribeOn(this, scheduler) is called to pass in itself and the scheduler
public final class ObservableSubscribeOn<T> extends AbstractObservableWithUpstream<T, T> { final Scheduler scheduler; public ObservableSubscribeOn(ObservableSource<T> source, Scheduler scheduler) { super(source); this.scheduler = scheduler; } }
ObservableSubscribeOn wraps up the objects returned by scheduler and create, and returns ObservableSubscribeOn
3.observeOn
One parameter is Scheduler
@SchedulerSupport(SchedulerSupport.CUSTOM) public final Observable<T> observeOn(Scheduler scheduler) { return observeOn(scheduler, false, bufferSize()); } @SchedulerSupport(SchedulerSupport.CUSTOM) public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) { ObjectHelper.requireNonNull(scheduler, "scheduler is null"); ObjectHelper.verifyPositive(bufferSize, "bufferSize"); return RxJavaPlugins.onAssembly(new ObservableObserveOn<T>(this, scheduler, delayError, bufferSize)); }
ObservableSubscribeOn (observable) also calls observeOn, and then calls new ObservableObserveOn(this, scheduler, delayError, bufferSize).
public final class ObservableObserveOn<T> extends AbstractObservableWithUpstream<T, T> { final Scheduler scheduler; final boolean delayError; final int bufferSize; public ObservableObserveOn(ObservableSource<T> source, Scheduler scheduler, boolean delayError, int bufferSize) { super(source); this.scheduler = scheduler; this.delayError = delayError; this.bufferSize = bufferSize; } }
It is also a wrapper that wraps ObservableSubscribeOn and scheduler into ObservableObserveOn
4.subscribe
The last step above is to call ObservableObserveOn.subscribe, and the passed in parameter is an observer
//ObservableObserveOn.java @SchedulerSupport(SchedulerSupport.NONE) @Override public final void subscribe(Observer<? super T> observer) { ObjectHelper.requireNonNull(observer, "observer is null"); try { observer = RxJavaPlugins.onSubscribe(this, observer); ObjectHelper.requireNonNull(observer, "Plugin returned null Observer"); subscribeActual(observer); } catch (NullPointerException e) { // NOPMD throw e; } catch (Throwable e) { Exceptions.throwIfFatal(e); // can't call onError because no way to know if a Disposable has been set or not // can't call onSubscribe because the call might have set a Subscription already RxJavaPlugins.onError(e); NullPointerException npe = new NullPointerException("Actually not, but can't throw other exceptions due to RS"); npe.initCause(e); throw npe; } }
You can see that after calling subscribe, you call subscribeActual(observer). Pass observer in
Let's take a look at subscribe actual (observer)
//ObservableObserveOn.java @Override protected void subscribeActual(Observer<? super T> observer) { if (scheduler instanceof TrampolineScheduler) { source.subscribe(observer); } else { Scheduler.Worker w = scheduler.createWorker(); source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize)); } }
The above if doesn't care. It mainly looks at the following logic and calls scheduler.createWorker(). This scheduler is imported by observeOn and then called.
new ObserveOnObserver(observer, w, delayError, bufferSize); Wrap the worker /observer again.
//ObservableObserveOn inner class static final class ObserveOnObserver<T> extends BasicIntQueueDisposable<T> implements Observer<T>, Runnable { private static final long serialVersionUID = 6576896619930983584L; final Observer<? super T> actual; final Scheduler.Worker worker; final boolean delayError; final int bufferSize; SimpleQueue<T> queue; Disposable s; Throwable error; volatile boolean done; volatile boolean cancelled; int sourceMode; boolean outputFused; ObserveOnObserver(Observer<? super T> actual, Scheduler.Worker worker, boolean delayError, int bufferSize) { this.actual = actual; this.worker = worker; this.delayError = delayError; this.bufferSize = bufferSize; } @Override public void onSubscribe(Disposable s) { if (DisposableHelper.validate(this.s, s)) { this.s = s; if (s instanceof QueueDisposable) { @SuppressWarnings("unchecked") QueueDisposable<T> qd = (QueueDisposable<T>) s; int m = qd.requestFusion(QueueDisposable.ANY | QueueDisposable.BOUNDARY); if (m == QueueDisposable.SYNC) { sourceMode = m; queue = qd; done = true; actual.onSubscribe(this); schedule(); return; } if (m == QueueDisposable.ASYNC) { sourceMode = m; queue = qd; actual.onSubscribe(this); return; } } queue = new SpscLinkedArrayQueue<T>(bufferSize); actual.onSubscribe(this); } } @Override public void onNext(T t) { if (done) { return; } if (sourceMode != QueueDisposable.ASYNC) { queue.offer(t); } schedule(); } @Override public void onError(Throwable t) { if (done) { RxJavaPlugins.onError(t); return; } error = t; done = true; schedule(); } @Override public void onComplete() { if (done) { return; } done = true; schedule(); } @Override public void dispose() { if (!cancelled) { cancelled = true; s.dispose(); worker.dispose(); if (getAndIncrement() == 0) { queue.clear(); } } } @Override public boolean isDisposed() { return cancelled; } void schedule() { if (getAndIncrement() == 0) { worker.schedule(this); } } void drainNormal() { int missed = 1; final SimpleQueue<T> q = queue; final Observer<? super T> a = actual; for (;;) { if (checkTerminated(done, q.isEmpty(), a)) { return; } for (;;) { boolean d = done; T v; try { v = q.poll(); } catch (Throwable ex) { Exceptions.throwIfFatal(ex); s.dispose(); q.clear(); a.onError(ex); return; } boolean empty = v == null; if (checkTerminated(d, empty, a)) { return; } if (empty) { break; } a.onNext(v); } missed = addAndGet(-missed); if (missed == 0) { break; } } } void drainFused() { int missed = 1; for (;;) { if (cancelled) { return; } boolean d = done; Throwable ex = error; if (!delayError && d && ex != null) { actual.onError(error); worker.dispose(); return; } actual.onNext(null); if (d) { ex = error; if (ex != null) { actual.onError(ex); } else { actual.onComplete(); } worker.dispose(); return; } missed = addAndGet(-missed); if (missed == 0) { break; } } } @Override public void run() { if (outputFused) { drainFused(); } else { drainNormal(); } } boolean checkTerminated(boolean d, boolean empty, Observer<? super T> a) { if (cancelled) { queue.clear(); return true; } if (d) { Throwable e = error; if (delayError) { if (empty) { if (e != null) { a.onError(e); } else { a.onComplete(); } worker.dispose(); return true; } } else { if (e != null) { queue.clear(); a.onError(e); worker.dispose(); return true; } else if (empty) { a.onComplete(); worker.dispose(); return true; } } } return false; } @Override public int requestFusion(int mode) { if ((mode & ASYNC) != 0) { outputFused = true; return ASYNC; } return NONE; } @Override public T poll() throws Exception { return queue.poll(); } @Override public void clear() { queue.clear(); } @Override public boolean isEmpty() { return queue.isEmpty(); } }
After wrapping ObserveOnObserver, the source.subscribe source here is called ObservableSubscribeOn.subscribe, and then ObservableSubscribeOn.subscribeActual is invoked.
//ObservableSubscribeOn.java @Override public void subscribeActual(final Observer<? super T> s) { final SubscribeOnObserver<T> parent = new scheduler<T>(s); s.onSubscribe(parent); parent.setDisposable(scheduler.scheduleDirect(new Runnable() { @Override public void run() { source.subscribe(parent); } })); } static final class SubscribeOnObserver<T> extends AtomicReference<Disposable> implements Observer<T>, Disposable { private static final long serialVersionUID = 8094547886072529208L; final Observer<? super T> actual; final AtomicReference<Disposable> s; SubscribeOnObserver(Observer<? super T> actual) { this.actual = actual; this.s = new AtomicReference<Disposable>(); } @Override public void onSubscribe(Disposable s) { DisposableHelper.setOnce(this.s, s); } @Override public void onNext(T t) { actual.onNext(t); } @Override public void onError(Throwable t) { actual.onError(t); } @Override public void onComplete() { actual.onComplete(); } @Override public void dispose() { DisposableHelper.dispose(s); DisposableHelper.dispose(this); } @Override public boolean isDisposed() { return DisposableHelper.isDisposed(get()); } void setDisposable(Disposable d) { DisposableHelper.setOnce(this, d); } }
ObservableSubscribeOn.subscribeActual
First, the incoming observer is encapsulated as SubscribeOnObserver
Then, onSubscribe is triggered, and then scheduler.scheduleDirect(new Runnable() is called. The scheduler here is passed in by subscribeOn
Finally, the scheduler.setsetDisposable method is invoked.
We see the method body of run is source.subscribe(parent); the source here is ObservableCreate (ObservableOnSubscribe), which is passed to observer, and then invokes observer's OnNext and OnComplete methods.
5. Summary:
a. Calling the Observer.OnSubscribe method is not affected by thread scheduling
b.subscribeOn affects the thread that sends the event
c.observerOn affects the thread that the observer processes and receives data. If observeOn is not called, it will not be packaged as ObserveOnObserver, that is, the observer's thread switching will not be executed, which is consistent with the sender's thread
d. When subscribeOn is called several times to switch threads, new ObservableSubscribeOn will be called each time. When the event is triggered, it will be called up, that is, the thread passed in by subscribeOn called for the first time will execute the send event, and the subsequent thread switching is invalid
e.Observer.OnSubscribe is executed only once because DisposableHelper.setOnce(this.s, s) is called
f. After onComplete or onError is processed, the event will not be issued again, because the observer will call disposed after sending these two events
Relevant video recommendations
How does thread switching in rxjava intervene in the original framework
Zero foundation of Android development from entry to mastery
This article is transferred from https://juejin.cn/post/6952831553349091358 , in case of infringement, please contact to delete.