Source code analysis of Android mainstream tripartite libraries: RxJava

1. What exactly is RxJava?

RxJava is a reactive extension library based on the Java virtual machine, which combines asynchronous and event-based programs by using observable sequences . At the same time, it extends the observer pattern to support data/event sequences , and adds operators that allow you to declaratively combine sequences while abstracting out the issues to be concerned about: such as low-level threads, synchronization, and thread safety And concurrent data structure, etc.

From the official definition of RxJava, if we want to truly understand RxJava, we must conduct an in-depth analysis of the following two parts:

  • 1. Subscription process
  • 2. Thread switching

Of course, the source code of RxJava operators is also a good learning resource, especially the source code of operators such as FlatMap and Zip. There are many places to learn from, but their internal implementation is more complicated and limited in space. This article only explains the subscription process of RxJava. And the principle of thread switching. Next, I will explain in detail the two key parts of RxJava.

Second, the subscription process of RxJava

First, give an example of RxJava message subscription:

Observable.create(newObservableOnSubscribe<String>() {
    @Override
    public void subscribe(ObservableEmitter<String>emitter) throws Exception {
        emitter.onNext("1");
        emitter.onNext("2");
        emitter.onNext("3");
        emitter.onComplete();
    }
}).subscribe(new Observer<String>() {
    @Override
    public void onSubscribe(Disposable d) {
        Log.d(TAG, "onSubscribe");
    }
    @Override
    public void onNext(String s) {
        Log.d(TAG, "onNext : " + s);
    }
    @Override
    public void onError(Throwable e) {
        Log.d(TAG, "onError : " + e.toString());
    }
    @Override
    public void onComplete() {
        Log.d(TAG, "onComplete");
    }
});
复制代码

As you can see, an observer is first created here, and then an observer is created to subscribe to the observer. Therefore, the following two parts analyze the subscription process of RxJava:

  • 1. The process of creating the observed
  • 2. Subscription process

1. The process of creating the observed

First of all, the above uses the create() method of the Observable class to create an observer and see what is done inside.

1.1、Observable#create()
// 省略一些检测性的注解
public static <T> Observable<T> create(ObservableOnSubscribe<T> source) {
    ObjectHelper.requireNonNull(source, "source is null");
    return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source));
}
复制代码

In Observable's create(), a new ObservableCreate object is actually created. At the same time, we pass the defined ObservableOnSubscribe object into the ObservableCreate object, and finally call the RxJavaPlugins.onAssembly() method. Next, take a look at what this ObservableCreate does.

1.2、ObservableCreate
public final class ObservableCreate<T> extends Observable<T> {

    final ObservableOnSubscribe<T> source;

    public ObservableCreate(ObservableOnSubscribe<T> source) {
        this.source = source;
    }

    ...
}
复制代码

Here just save the object ObservableOnSubscribe in ObservableCreate. Then look at the processing of the RxJavaPlugins.onAssembly() method.

1.3、RxJavaPlugins#onAssembly()
public static <T> Observable<T> onAssembly(@NonNull Observable<T> source) {

    // 应用hook函数的一些处理,一般用到不到
    ...
    return source;
}
复制代码

In the end it just returned our ObservableCreate.

1.4 Summary of the process of creating the observed

From the above analysis, the Observable.create() method just repackages our custom ObservableOnSubscribe object into an ObservableCreate object .

2. Subscription process

Next, look at how the subscription process of Observable.subscribe() is implemented.

2.1、Observable#subscribe()
public final void subscribe(Observer<? super T> observer) {
    ...

    // 1
    observer = RxJavaPlugins.onSubscribe(this,observer);

    ...

    // 2
    subscribeActual(observer);

    ...
}
复制代码

In Note 1, the onSubscribe() method of RxJavaPlugins is first called within the subscribe() method of Observable.

2.2、RxJavaPlugins#onSubscribe()
public static <T> Observer<? super T> onSubscribe(@NonNull Observable<T> source, @NonNull Observer<? super T> observer) {

    // 应用hook函数的一些处理,一般用到不到
    ...

    return observer;
}
复制代码

Excluding the logic of the hook application, here is just returning the observer. Next, let’s analyze the subscribeActual() method in note 2.

2.3、Observable#subscribeActual()
protected abstract void subscribeActual(Observer<? super T> observer);
复制代码

This is an abstract method. Obviously, its corresponding concrete implementation class is the ObservableCreate class we created in the first step, and then we will see the subscribeActual() method of ObservableCreate.

2.4、ObservableCreate#subscribeActual()
@Override
protected void subscribeActual(Observer<? super T> observer) {
    // 1
    CreateEmitter<T> parent = new CreateEmitter<T>(observer);
    // 2
    observer.onSubscribe(parent);

    try {
        // 3
        source.subscribe(parent);
    } catch (Throwable ex) {
        Exceptions.throwIfFatal(ex);
        parent.onError(ex);
    }
}
复制代码

In Note 1, first a CreateEmitter object is newly created, and our custom observer object is passed in.

2.4.1、CreateEmitter
static final class CreateEmitter<T>
extends AtomicReference<Disposable>
implements ObservableEmitter<T>, Disposable {

    ...

    final Observer<? super T> observer;

    CreateEmitter(Observer<? super T> observer) {
        this.observer = observer;
    }

    ...
}
复制代码

As can be seen from the above, CreateEmitter guarantees the consistency of the event flow cut-off state Dispose by inheriting the atomic reference class AtomicReference in the Java concurrency package (if you don’t understand here, you will understand when you see Dispose later), and implement it ObservableEmitter interface and Disposable interface , and then we analyze the observer.onSubscribe(parent) in Note 2. The meaning of this onSubscribe callback is actually to tell the observer that the observer has successfully subscribed to the observer . Then see the source.subscribe(parent) line of code in Note 3. The source here is actually an ObservableOnSubscribe object. We see the subscribe() method of ObservableOnSubscribe.

2.4.2、ObservableOnSubscribe#subscribe()
Observable observable = Observable.create(new ObservableOnSubscribe<String>() {
    @Override
    public voidsubscribe(ObservableEmitter<String> emitter) throws Exception {
        emitter.onNext("1");
        emitter.onNext("2");
        emitter.onNext("3");
        emitter.onComplete();
    }
});
复制代码

Here, ObservableEmitter's onNext() method is used to send the event stream, and finally the onComplete() method is called to complete the subscription process. ObservableEmitter is an abstract class. The implementation class is the CreateEmitter object we passed in. Next, let's look at the processing of CreateEmitter's onNext() method and onComplete() method.

2.4.3、CreateEmitter#onNext() && CreateEmitter#onComplete()
static final class CreateEmitter<T>
extends AtomicReference<Disposable>
implements ObservableEmitter<T>, Disposable {

...

@Override
public void onNext(T t) {
    ...

    if (!isDisposed()) {
        //调用观察者的onNext()
        observer.onNext(t);
    }
}

@Override
public void onComplete() {
    if (!isDisposed()) {
        try {
            observer.onComplete();
        } finally {
            dispose();
        }
    }
}

...

}
复制代码

In CreateEmitter's onNext and onComplete methods, an isDisposed judgment must first be passed . The function is to see whether the current event stream is cut off (abandoned) . The default is not to cut off. If you want to cut off, you can call Disposable's dispose( ) Method to set this state to cut off (discard) state. We continue to look at the internal processing of this isDisposed.

2.4.4、ObservableEmitter#isDisposed()
@Override
public boolean isDisposed() {
    return DisposableHelper.isDisposed(get());
}
复制代码

Note that the saved Disposable state is first obtained from the AtomicReference of ObservableEmitter through the get() method. Then hand it over to DisposableHelper for judgment processing. Next, look at the processing of DisposableHelper.

2.4.5、DisposableHelper#isDisposed() && DisposableHelper#set()
public enum DisposableHelper implements Disposable {

    DISPOSED;

    public static boolean isDisposed(Disposable d) {
        // 1
        return d == DISPOSED;
    }

    public static boolean set(AtomicReference<Disposable> field, Disposable d) {
        for (;;) {
            Disposable current = field.get();
            if (current == DISPOSED) {
                if (d != null) {
                    d.dispose();
                }
                return false;
            }
            // 2
            if (field.compareAndSet(current, d)) {
                if (current != null) {
                    current.dispose();
                }
                return true;
            }
        }
    }

    ...

    public static boolean dispose(AtomicReference<Disposable> field) {
        Disposable current = field.get();
        Disposable d = DISPOSED;
        if (current != d) {
            // ...
            current = field.getAndSet(d);
            if (current != d) {
                if (current != null) {
                    current.dispose();
                }
                return true;
            }
        }
        return false;
    }

    ...
}
复制代码

DisposableHelper is an enumeration class with only one value inside, namely DISPOSED. From the above analysis, it can be seen that it is used to mark the event stream being cut off (discarded) . First see the code field.compareAndSet(current, d) and field.getAndSet(d) in Note 2 and Note 3. Here , the CAS method wrapped inside the atomic reference AtomicReference is used to deal with the concurrent reading and writing of the flag Disposable . Finally, see note 3, compare the Dispable state saved by the atom reference class we passed in CreateEmitter with the DISPOSED inside DisposableHelper. If they are equal, it proves that the data stream is cut off. In order to further understand the role of Disposed, let's take a look at the remaining key methods in CreateEmitter.

2.4.6、CreateEmitter
@Override
public void onNext(T t) {
    ...
    // 1
    if (!isDisposed()) {
        observer.onNext(t);
    }
}

@Override
public void onError(Throwable t) {
    if (!tryOnError(t)) {
        // 2
        RxJavaPlugins.onError(t);
    }
}

@Override
public boolean tryOnError(Throwable t) {
    ...
    // 3
    if (!isDisposed()) {
        try {
            observer.onError(t);
        } finally {
            // 4
            dispose();
        }
        return true;
    }
    return false;
}

@Override
public void onComplete() {
    // 5
    if (!isDisposed()) {
        try {
            observer.onComplete();
        } finally {
            // 6
            dispose();
        }
    }
}
复制代码

At notes 1, 3, and 5, the onNext() and onError() and onComplete() methods will first determine whether the event stream is cut off. If the event stream is cut off at this time, then onNext() and onComplete() will exit Method body, without processing, onError() will execute to the RxJavaPlugins.onError(t) code, and an exception will be thrown directly inside, causing a crash . If the event flow is not cut off, then the dispose() code in comments 4 and 6 will be called in the onError() and onComplete() to cut off the event flow. It can be seen that onError() and onComplete( ) Can only call one. If onComplete() is executed first, and then onError() is called, it will cause an abnormal crash .

Three, RxJava thread switching

First, give an example of RxJava thread switching:

Observable.create(new ObservableOnSubscribe<String>() {
    @Override
    public voidsubscribe(ObservableEmitter<String>emitter) throws Exception {
        emitter.onNext("1");
        emitter.onNext("2");
        emitter.onNext("3");
        emitter.onComplete();
    }
}) 
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<String>() {
        @Override
        public void onSubscribe(Disposable d) {
            Log.d(TAG, "onSubscribe");
        }
        @Override
        public void onNext(String s) {
            Log.d(TAG, "onNext : " + s);
        }
        @Override
        public void onError(Throwable e) {
            Log.d(TAG, "onError : " +e.toString());
        }
        @Override
        public void onComplete() {
            Log.d(TAG, "onComplete");
        }
});
复制代码

It can be seen that the thread switching of RxJava is mainly divided into the subscribeOn() and observeOn() methods . First, let's analyze the subscribeOn() method.

1、subscribeOn(Schedulers.io())

In the Scheduler.io() method, we need to pass in a Scheduler scheduling class first. Here is a scheduling class that is scheduled to the io child thread. Let’s take a look at how this schedule is constructed in the Scheduler.io() method. Of the device.

2、Schedulers#io()

static final Scheduler IO;

...

public static Scheduler io() {
    // 1
    return RxJavaPlugins.onIoScheduler(IO);
}

static {
    ...

    // 2
    IO = RxJavaPlugins.initIoScheduler(new IOTask());
}

static final class IOTask implements Callable<Scheduler> {
    @Override
    public Scheduler call() throws Exception {
        // 3
        return IoHolder.DEFAULT;
    }
}

static final class IoHolder {
    // 4
    static final Scheduler DEFAULT = new IoScheduler();
}
复制代码

There are a lot of codes for the Schedulers class. Here I will only explain the logic code involved in the Schedulers.io method. First of all, in Note 1, the same as the processing of the subscription process analyzed above, it is just a logic for processing hooks, and the final return is the incoming IO object. See note 2 again . The IO object is initialized in the static code block of Schedulers. The essence is to create a static internal class of IOTask. In the call method of IOTask, that is, note 3, you can understand the use The created IOScheduler object is returned in the way of static inner class. After going around such a big circle, the essence of the Schedulers.io method is to return an IOScheduler object .

3、Observable#subscribeOn()

  public final Observable<T> subscribeOn(Scheduler scheduler) {
    ...

    return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
}
复制代码

In the subscribeOn() method, ObservableCreate is wrapped into an ObservableSubscribeOn object. We are concerned about the ObservableSubscribeOn class.

4 、 ObservableSubscribeOn

public final class ObservableSubscribeOn<T> extends AbstractObservableWithUpstream<T, T> {
    final Scheduler scheduler;

    public ObservableSubscribeOn(ObservableSource<T> source, Scheduler scheduler) {
        // 1
        super(source);
        this.scheduler = scheduler;
    }

    @Override
    public void subscribeActual(final Observer<? super T> observer) {
        // 2
        final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(observer);

        // 3
        observer.onSubscribe(parent);

        // 4
        parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
    }

...
}
复制代码

First, in Note 1, save the incoming source and scheduler. Then, when the actual subscription is completed, the subscribeActual method will be executed. In Note 2, our custom Observer is packaged into a SubscribeOnObserver object. In Note 3, the observer is notified that the observer is subscribed. In note 4, a SubscribeTask object is first created internally to see its implementation.

5、ObservableSubscribeOn#SubscribeTask

final class SubscribeTask implements Runnable {
    private final SubscribeOnObserver<T> parent;

    SubscribeTask(SubscribeOnObserver<T> parent) {
        this.parent = parent;
    }

    @Override
    public void run() {
        source.subscribe(parent);
    }
}
复制代码

SubscribeTask is an internal class of ObservableSubscribeOn. It is essentially a task class. In its run method, it will execute the subscription method of source.subscribe(parent). This source is actually the ObservableCreate object passed in in the ObservableSubscribeOn constructor . Next, look at the internal processing of scheduler.scheduleDirect().

6、Scheduler#scheduleDirect()

public Disposable scheduleDirect(@NonNull Runnable run) {
    return scheduleDirect(run, 0L, TimeUnit.NANOSECONDS);
}

public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {

    // 1
    final Worker w = createWorker();

    // 2
    final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);

    // 3
    DisposeTask task = new DisposeTask(decoratedRun, w);

    // 4
    w.schedule(task, delay, unit);

    return task;
}
复制代码

Here will finally be executed to the above scheduleDirect () overload method. First of all, in Note 1, the createWorker() method will be called to create a worker object Worker, which is an abstract class. The implementation class here is IoScheduler. Next, let’s look at the createWorker() method of the IoScheduler class.

6.1、IOScheduler#createWorker()
final AtomicReference<CachedWorkerPool> pool;

...

public IoScheduler(ThreadFactory threadFactory) {
    this.threadFactory = threadFactory;
    this.pool = new AtomicReference<CachedWorkerPool>(NONE);
    start();
}

...

@Override
public Worker createWorker() {
    // 1
    return new EventLoopWorker(pool.get());
}

static final class EventLoopWorker extends Scheduler.Worker {
    ...

    EventLoopWorker(CachedWorkerPool pool) {
        this.pool = pool;
        this.tasks = new CompositeDisposable();
        // 2
        this.threadWorker = pool.get();
    }

}
复制代码

First, the pool.get() method is called in Note 1. Pool is an atomic reference object of type CachedWorkerPool , and its function is to cache the worker object Worker . Then, pass the obtained CachedWorkerPool into the newly created EventLoopWorker object. Focus on note 2 where the threadWorker object cached by CachedWorkerPool is saved.

Below, we continue to analyze the code in Note 2 of the code segment in 3.6. Here is another encapsulation process about hook, and finally the current Runnable object returned. In Note 3, a new cut off task DisposeTask was created to wrap decoratedRun and w objects. Finally, the schedule() method of the worker is called at Note 4. Let's analyze its internal processing.

6.2、IoScheduler#schedule()
@Override
public Disposable schedule(@NonNull Runnableaction, long delayTime, @NonNull TimeUnit unit){
    ...

    return threadWorker.scheduleActual(action,delayTime, unit, tasks);
}
复制代码

The scheduleActual() method of threadWorker is called internally, which actually calls the scheduleActual() method of the parent class NewThreadWorker. Let’s continue to look at what is done in the scheduleActual() method of NewThreadWorker.

6.3、NewThreadWorker#scheduleActual()
public NewThreadWorker(ThreadFactory threadFactory) {
    executor = SchedulerPoolFactory.create(threadFactory);
}

@NonNull
public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
    Runnable decoratedRun = RxJavaPlugins.onSchedule(run);

    // 1
    ScheduledRunnable sr = new ScheduledRunnable(decoratedRun, parent);

    if (parent != null) {
        if (!parent.add(sr)) {
            return sr;
        }
    }

    Future<?> f;
    try {
        // 2
        if (delayTime <= 0) {
            // 3
            f = executor.submit((Callable<Object>)sr);
        } else {
            // 4
            f = executor.schedule((Callable<Object>)sr, delayTime, unit);
        }
        sr.setFuture(f);
    } catch (RejectedExecutionException ex) {
        if (parent != null) {
            parent.remove(sr);
        }
        RxJavaPlugins.onError(ex);
    }

    return sr;
}
复制代码

Inside the scheduleActual() method of NewThreadWorker, in Note 1, a ScheduledRunnable object will be created first to wrap the Runnable object and the parent. Here parent is a DisposableContainer object, and its actual implementation class is the CompositeDisposable class, which is a save The internal implementation of the container for whether all event streams are cut off or not is stored using a simple OpenHashSet class defined by RxJava itself . At last note 2, judge whether the delay time is set, if it is set, call the submit() method of the thread pool to immediately switch the thread, otherwise, call the schedule() method to delay the execution of the thread switch.

7. Why is subscribeOn() executed multiple times, only the first time it works?

From the above analysis, we can easily understand that when the observer is subscribed, it is notified from the outermost layer (ObservableSubscribeOn) to the inner layer (ObservableOnSubscribe) . When the subscribeOn() is executed multiple times continuously, In fact, it is to execute the subscribeOn() method from the penultimate, until the subscribeOn() method executed last, which will definitely cover the previous thread switching.

8、observeOn(AndroidSchedulers.mainThread())

public final Observable<T> observeOn(Scheduler scheduler) {
    return observeOn(scheduler, false, bufferSize());
}

public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
    ....

    return RxJavaPlugins.onAssembly(new ObservableObserveOn<T>(this, scheduler, delayError, bufferSize));
}
复制代码

As you can see, the observeOn() method finally returns an ObservableObserveOn object. Let’s take a look directly at the subscribeActual() method of ObservableObserveOn.

9、ObservableObserveOn#subscribeActual()

@Override
protected void subscribeActual(Observer<? super T> observer) {
    // 1
    if (scheduler instanceof TrampolineScheduler) {
        // 2
        source.subscribe(observer);
    } else {
        // 3
        Scheduler.Worker w = scheduler.createWorker();
        // 4
        source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
    }
}
复制代码

First, at Note 1, determine whether the specified scheduler is TrampolineScheduler, which is a scheduler that executes the current code immediately without thread switching. If it is, it will directly call the subscribe() method of ObservableSubscribeOn. If it is not, it will create a worker object at Note 3. Then, create a new ObserveOnObserver at note 4 to wrap the SubscribeOnobserver object, and pass it to the subscribe() method of ObservableSubscribeOn to subscribe. Next, look at the key methods of the ObserveOnObserver class.

10、ObserveOnObserver

@Override
public void onNext(T t) {
    ...
    if (sourceMode != QueueDisposable.ASYNC) {
        // 1
        queue.offer(t);
    }
    schedule();
}

@Override
public void onError(Throwable t) {
    ...
    schedule();
}

@Override
public void onComplete() {
    ...
    schedule();
}
复制代码

To remove the non-mainline logic code, the schedule() method is finally called in the onNext(), onError() and onComplete() methods of ObserveOnObserver. Then look at the schedule() method, where onNext() also stores the message in the queue .

11、ObserveOnObserver#schedule()

void schedule() {
    if (getAndIncrement() == 0) {
        worker.schedule(this);
    }
}
复制代码

The worker is used here to schedule ObserveOnObserver, which implements the task of Runnable. The worker is created in AndroidSchedulers.mainThread(). In fact, the Handler is used for thread switching internally, so I won't repeat it here. Then look at the run() method of ObserveOnObserver.

12、ObserveOnObserver#run()

@Override
public void run() {
    // 1
    if (outputFused) {
        drainFused();
    } else {
        // 2
        drainNormal();
    }
}
复制代码

In Note 1, the flag bit outputFused will be judged first. It indicates whether the event stream is melted. The default is false, so the drainNormal() method will be executed in the end . Then look at the internal processing of the drainNormal() method.

13 、 ObserveOnObserver # drainNormal ()

void drainNormal() {
    int missed = 1;

    final SimpleQueue<T> q = queue;

    // 1
    final Observer<? super T> a = downstream;

    ...

    // 2
    v = q.poll();

    ...
    // 3
    a.onNext(v);

    ...
}
复制代码

In Note 1, the downstream here is actually the SubscribeOnObserver object passed in from outside. At note 2, the message in the queue is taken out, and then at note 3, the onNext method of SubscribeOnObserver is called. In the end, it will be called from the outermost layer of our packaging class to the innermost onNext() method in our custom Observer, so the chain code below the observeOn() method will be executed in the thread specified by it , Oh, that's it .

Five, summary

In fact, I have used RxJava for more than a year, but I haven't thoroughly understood its internal implementation principles. Now I have tasted it carefully, and it is indeed hearty . From OkHttp at the beginning to the current RxJava source code analysis, so far, five articles have been published in the Android mainstream third-party library source code analysis series. Our journey has passed halfway. Next, I will talk about memory leaks in Android. LeakCanary framework source code is explained in depth, please look forward to it~

Six, study notes sharing

In order to facilitate everyone to learn more about Android-related source code, the third framework has been added. I have compiled a copy of "Android Related Source Code Analysis" and "Design Ideas Interpretation of Open Source Framework", partners in need can like + follow, and send me a private message!

Android related source code analysis
Interpretation of open source framework for design thinking

Rxjava related analysis content

Guess you like

Origin blog.csdn.net/star_nwe/article/details/112279711