Введение
-
Цели обучения этой статьи:
-
Знания системы Rxjava довольно большие, и мы изучаем только вышеуказанный контент, во-вторых, детали исходного кода относительно сложны, и мы в основном сосредоточены на разъяснении принципов, и не будем вдаваться в подробности;
-
Понятия, требующие уточнения: наблюдатель, наблюдатель, подписка, наблюдатель восходящего/нисходящего потока, наблюдатель восходящего/нисходящего потока Эти понятия будут объяснены в конкретных сценариях ниже;
-
Проверьте некоторые выводы:
- Проверка 1: нижестоящий наблюдатель содержит ссылку на вышестоящего наблюдателя;
- Проверка 2: вышестоящий наблюдатель содержит ссылку на нижестоящего наблюдателя;
- Проверка 3: нижестоящий наблюдатель инициирует подписку вышестоящего наблюдателя;
- Проверка 4: нижестоящий наблюдатель вызовет метод нижестоящего наблюдателя, «удерживая» ссылку нижестоящего наблюдателя;
2. Сценарий 1: без оператора, без переключения потоков
- Код выглядит следующим образом (для облегчения изучения и понимания некоторые китайские иероглифы используются в качестве переменных, и выбрано Single)
//1.创建被观察者
var 被观察者 = Single.just("123") //分析1
//2.创建观察者
var 观察者 = object : SingleObserver<String> {
override fun onSuccess(t: String) {
println("test ---> $t")
}
override fun onSubscribe(d: Disposable) {
}
override fun onError(e: Throwable) {
}
}
//3.被观察者订阅观察者
被观察者.subscribe(观察者) //分析2
- Вышеприведенный код будет передавать параметры в методе just методу onSuccess анонимного внутреннего класса SingleObserver, мы разберем, как это реализовано шаг за шагом;
- Взгляните на исходный код Анализа 1: создание наблюдаемого
//Single.java
public static <T> Single<T> just(final T item) {
ObjectHelper.requireNonNull(item, "item is null");//校验,忽略
return RxJavaPlugins.onAssembly(new SingleJust<T>(item));//RxJavaPlugins.onAssembly,钩子函数,忽略
}
//SingleJust.java
public final class SingleJust<T> extends Single<T> {
final T value;
public SingleJust(T value) {
this.value = value;
}
@Override
protected void subscribeActual(SingleObserver<? super T> observer) {
observer.onSubscribe(Disposables.disposed());
observer.onSuccess(value);
}
}
- Single.just("123") фактически создает объект SingleJust, который является наблюдателем . Наблюдатель создается через анонимный внутренний класс SingleObserver, а подписка соответствует методу подписки;
- Взгляните на исходный код Analysis 2:
//Single.java
public final void subscribe(SingleObserver<? super T> observer) {
ObjectHelper.requireNonNull(observer, "observer is null");
observer = RxJavaPlugins.onSubscribe(this, observer);
ObjectHelper.requireNonNull(observer, "The RxJavaPlugins.onSubscribe hook returned a null SingleObserver. Please check the handler provided to RxJavaPlugins.setOnSingleSubscribe for invalid null returns. Further reading: https://github.com/ReactiveX/RxJava/wiki/Plugins");
try {
subscribeActual(observer);//分析3
} catch (NullPointerException ex) {
throw ex;
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
NullPointerException npe = new NullPointerException("subscribeActual failed");
npe.initCause(ex);
throw npe;
}
}
- В позиции анализа 2 переменная "observed" указывает на объект SingleJust (полиморфизм), тогда соответствующий анализ 3 может знать, что будет выполнен метод subscribeActual объекта SingleJust, взгляните на исходный код
//其中,方法中的参数为分析2位置中传递的观察者
protected void subscribeActual(SingleObserver<? super T> observer) {
//调用观察者的onSubscribe和onSuccess方法
observer.onSubscribe(Disposables.disposed());
observer.onSuccess(value);
}
- Благодаря Сценарию 1 у нас есть понимание Observer / Observer / Subscription .
- Анализ исходного кода вышеприведенных трех шагов на самом деле означает, что <observed> будет «удерживать» (на самом деле не удерживать, а передавать наблюдателю через метод) ссылку <observer>, когда <observed> вызывает метод подписки (подписки). , он будет использовать ссылку <observer> для вызова собственного метода <observer>; таким образом, события, сгенерированные из <observed> <Давайте сначала поймем это как данные, и мы поймем это в будущем, хотя в некоторой степени нерегулярно, это хорошо для обучения> будет передано в метод <наблюдателя>, после вышеописанного анализа <данные> образуют поток. Давайте немного усложним, добавив карту операторов.
3. Сценарий 2: Добавить оператора карты на основе сценария 1.
- код показывает, как показано ниже
//1.创建被观察者
var 被观察者2 = Single.just("123")
//2.创建观察者
var 观察者2 = object : SingleObserver<String> {
override fun onSuccess(t: String) {
println("test ---> $t")
}
override fun onSubscribe(d: Disposable) {
}
override fun onError(e: Throwable) {
}
}
//3.调用map操作符(创建新的被观察者)
var 被观察者3 = 被观察者2
.map { it -> "$it ---> 操作符原理" } //分析4
//4.<被观察者3>调用订阅方法
被观察者3.subscribe(观察者2) //位置5
- Взгляните на исходный код Analysis 4
public final <R> Single<R> map(Function<? super T, ? extends R> mapper) {
ObjectHelper.requireNonNull(mapper, "mapper is null");
return RxJavaPlugins.onAssembly(new SingleMap<T, R>(this, mapper)); //分析5
}
- Местоположение анализа 5 на самом деле предназначено для создания объекта SingleMap (та же предыдущая функция ловушки игнорируется), через сценарий 1 мы можем проанализировать, что «наблюдаемое 2» указывает на SingleJust, то есть первое из SingleMap в местоположении анализа 5. Параметр — SingleJust, а второй параметр передается из позиции анализа 4. Тогда «observed 3» в позиции 5 фактически указывает на SingleMap. Сценарий 1 известен);
- Проанализируйте исходный код метода subscribeActual для SingleMap.
public final class SingleMap<T, R> extends Single<R> {
final SingleSource<? extends T> source;
final Function<? super T, ? extends R> mapper;
public SingleMap(SingleSource<? extends T> source, Function<? super T, ? extends R> mapper) {
this.source = source;
this.mapper = mapper;
}
@Override
protected void subscribeActual(final SingleObserver<? super R> t) {
//分析6
source.subscribe(new MapSingleObserver<T, R>(t, mapper));
}
static final class MapSingleObserver<T, R> implements SingleObserver<T> {
final SingleObserver<? super R> t;
final Function<? super T, ? extends R> mapper;
MapSingleObserver(SingleObserver<? super R> t, Function<? super T, ? extends R> mapper) {
this.t = t;
this.mapper = mapper;
}
@Override
public void onSubscribe(Disposable d) {
t.onSubscribe(d);//位置7
}
@Override
public void onSuccess(T value) {
R v;
try {
v = ObjectHelper.requireNonNull(mapper.apply(value), "The mapper function returned a null value.");
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
onError(e);
return;
}
t.onSuccess(v);//位置8
}
@Override
public void onError(Throwable e) {
t.onError(e);
}
}
}
-
Взгляните на код для Анализа 6
- Благодаря анализу 5 мы знаем, что источник анализа 6 представляет SingleJust, а логика анализа 6 заключается в том, что операция подписки выполняется через ссылку SingleJust, Параметром метода подписки является новый наблюдатель (MapSingleObserver), а новый наблюдатель содержит " Observer 2", а параметр картографа передается через оператор карты.
- Когда SingleJust выполняет метод подписки, он запускает метод subscribeActual SingleJust, в сочетании с предыдущим анализом он выполняет методы onSubscribe и onSuccess MapSingleObserver. Таким образом, позиция 7 и позиция 8 будут выполнять методы onSubscribe и onSuccess "Observer 2".
-
В этот момент параметры, переданные в позиции «Observed 2», передаются в соответствующий метод обратного вызова «Observer 2», то есть при добавлении оператора карты логика подписки и логика передачи <data> выпрямляются. .
-
Резюмируем с картинкой:
-
Наблюдатели, созданные вызовами API сверху вниз, называются вышестоящими наблюдателями и нижестоящими наблюдателями.Наблюдатели, которые мы активно создаем, называются нижестоящими наблюдателями.На этом рисунке показано, что во время вызова API происходит создание соответствующего наблюдаемого и создание вышестоящего наблюдателя. В то же время отношения между наблюдаемым и наблюдаемым, между наблюдаемым и наблюдателем;
-
До сих пор были разъяснены концепции, которые необходимо прояснить, и выводы, которые необходимо проверить, упомянутые в предисловии. Давайте резюмируем основные принципы Rxjava : когда самый нижний наблюдатель подписывается на самого нижнего наблюдателя (соответствует коду в нижней части API на рисунке выше), новый наблюдатель будет создан как вышестоящий по отношению к нижестоящему наблюдателю и удерживайте нижестоящего наблюдателя, что заставит вышестоящего наблюдателя подписаться на вновь созданного вышестоящего наблюдателя. Когда самый вышестоящий наблюдатель выполняет метод подписки, он вызывает свой собственный метод subscribeActual, который вызывает API самого вышестоящего наблюдателя.Поскольку вышестоящий наблюдатель удерживает нижестоящего наблюдателя, он инициирует вызов метода нижестоящего наблюдателя до тех пор, пока запускается обратный вызов в самом нижестоящем наблюдателе, определенном нами. То есть подписка инициируется постепенно от нисходящего к восходящему потоку, и данные передаются от восходящего к нисходящему постепенно.
4. Сценарий 3. Добавьте переключение потоков на основе сценария 2.
- Сценарий 3 — анализ принципа переключения потоков
4.1.подписка по принципу переключения тем
Single.just("123").map { it -> "$it ---> 操作符原理" }
.subscribeOn(Schedulers.io())//分析9
.observeOn(AndroidSchedulers.mainThread())//分析10
.subscribe(object : SingleObserver<String> {
override fun onSuccess(t: String) {
}
override fun onSubscribe(d: Disposable) {
}
override fun onError(e: Throwable) {
}
})
- Посмотреть исходный код Analysis 9
//Single.java
public final Single<T> subscribeOn(final Scheduler scheduler) {
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
return RxJavaPlugins.onAssembly(new SingleSubscribeOn<T>(this, scheduler)); //分析11
}
- Посмотреть исходный код Analysis 11
//SingleSubscribeOn.java
public final class SingleSubscribeOn<T> extends Single<T> {
final SingleSource<? extends T> source;
final Scheduler scheduler;
public SingleSubscribeOn(SingleSource<? extends T> source, Scheduler scheduler) {
this.source = source;
this.scheduler = scheduler;
}
@Override
protected void subscribeActual(final SingleObserver<? super T> observer) {
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(observer, source);
observer.onSubscribe(parent);
Disposable f = scheduler.scheduleDirect(parent);//分析12
parent.task.replace(f);
}
static final class SubscribeOnObserver<T>
extends AtomicReference<Disposable>
implements SingleObserver<T>, Disposable, Runnable {
//...
public void run() {
source.subscribe(this);
}
}
}
- Посмотреть исходный код Analysis 12
//抽象类 Scheduler.java
public Disposable scheduleDirect(@NonNull Runnable run) {
return scheduleDirect(run, 0L, TimeUnit.NANOSECONDS);//分析13
}
//分析13的源码
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
final Worker w = createWorker();//分析14
final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);//钩子函数,忽略
DisposeTask task = new DisposeTask(decoratedRun, w);//位置15
w.schedule(task, delay, unit);//分析16
return task;
}
- Посмотреть исходный код Анализа 14
public abstract Worker createWorker();
//会执行其子类的createWorker,具体的是IoScheduler类的createWorker方法,因为在调用subscribeOn(Schedulers.io())时传入了Schedulers.io(),而通过分析Schedulers.io()就可以知道。
- Анализ Schedulers.io()
//Schedulers.java
public static Scheduler io() {
return RxJavaPlugins.onIoScheduler(IO);//忽略钩子函数,查看IO即可
}
static {
//...
IO = RxJavaPlugins.initIoScheduler(new IOTask());//忽略钩子函数,查看IOTask
//...
}
static final class IOTask implements Callable<Scheduler> {
@Override
public Scheduler call() throws Exception {
return IoHolder.DEFAULT;
}
}
//查看IoHolder.DEFAULT
static final class IoHolder {
static final Scheduler DEFAULT = new IoScheduler();
}
- Теперь мы знаем позицию анализа 14, метод createWorker вызовет метод createWorker класса IoScheduler, войдет в представление, и мы сможем узнать, что Worker указывает на EventLoopWorker.
//IoScheduler.java
public Worker createWorker() {
return new EventLoopWorker(pool.get());
}
static final class EventLoopWorker extends Scheduler.Worker {
//...
EventLoopWorker(CachedWorkerPool pool) {
this.pool = pool;
this.tasks = new CompositeDisposable();
this.threadWorker = pool.get();
}
//...
@NonNull
@Override
public Disposable schedule(@NonNull Runnable action, long delayTime, @NonNull TimeUnit unit) {
if (tasks.isDisposed()) {
// don't schedule, we are unsubscribed
return EmptyDisposable.INSTANCE;
}
return threadWorker.scheduleActual(action, delayTime, unit, tasks);//分析17
}
}
- Позиция 15 инкапсулирует Work and run (новый наблюдатель передан), анализ 16 в конечном итоге выполнит метод scheduleActual EventLoopWorker и, наконец, выполнится до позиции анализа 17.
public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
Runnable decoratedRun = RxJavaPlugins.onSchedule(run);//钩子函数,忽略
ScheduledRunnable sr = new ScheduledRunnable(decoratedRun, parent);//位置18
if (parent != null) {
if (!parent.add(sr)) {
return sr;
}
}
Future<?> f;
try {
if (delayTime <= 0) {
f = executor.submit((Callable<Object>)sr);//分析19
} else {
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;
}
- ДекорированныйRun на позиции 18 фактически является первым запуском параметра метода scheduleActual, то есть предыдущего DisposeTask.Поскольку delayTime равно 0, он будет выполняться до анализа 19. Здесь используется пул потоков, а вызов метода sr (ScheduledRunnable) будет выполнен в конце концов. () метод, см. метод call() ScheduledRunnable
public final class ScheduledRunnable extends AtomicReferenceArray<Object>
implements Runnable, Callable<Object>, Disposable {
//...
public ScheduledRunnable(Runnable actual, DisposableContainer parent) {
super(3);
this.actual = actual;
this.lazySet(0, parent);
}
//...
public Object call() {
// Being Callable saves an allocation in ThreadPoolExecutor
run();
return null;
}
@Override
public void run() {
lazySet(THREAD_INDEX, Thread.currentThread());
try {
try {
actual.run();//分析20
} catch (Throwable e) {
//...
}
} finally {
//...
}
}
//...
}
- Позже он будет выполнен до позиции анализа 20, а фактический параметр — DisposeTask, и, наконец, будет выполнен метод запуска DisposeTask.
//Scheduler.java
public void run() {
runner = Thread.currentThread();
try {
decoratedRun.run();//分析21
} finally {
dispose();
runner = null;
}
}
- Анализ 21, благодаря предыдущему анализу мы можем знать, что decorRun это SubscribeOnObserver, то есть будет выполнен метод run у SubscribeOnObserver, проверьте его метод
//SingleSubscribeOn.java的内部类SubscribeOnObserver
public void run() {
source.subscribe(this);//执行上游的订阅操作
}
- На данный момент мы ясно понимаем принцип подписки на переключение потоков : сначала переключаем потоки, а затем подписываемся на вышестоящего наблюдателя.
- Когда subscribeOn вызывается несколько раз, вступает в силу только один из вызовов subscribeOn, вызванный в первый раз (поскольку вступит в силу только самый верхний по течению);
4.2.Принцип наблюдения за переключением потоков
- После выяснения принципа подписки на переключение потоков, принцип наблюдения за переключением потоков на самом деле проще.Вы можете разобрать исходный код по анализу в 4.1, а заключение написать прямо здесь.
- Принцип наблюдаемого при переключении потоков : сначала сделать подписку вышестоящего наблюдателя, а затем переключать поток, когда вышестоящий наблюдатель уведомит нижестоящего наблюдателя. Переключается именно нисходящий поток, то есть переключение потоков не выполняется, когда восходящий поток подписывается наблюдателем, а переключение потоков выполняется при получении данных, переданных восходящим потоком .
5. (Понимание) принцип работы одноразовых
- Так как одноразовый очень сложный и личных исследований не так много, здесь лишь краткое упоминание.
- Его можно просто разделить на две категории: с последующим наблюдением и без последующего наблюдения.
- Если есть последующая отмена, он найдет апстрим, если нет продолжения, если отменяется, ничего не сделает.
6. Рукописная Rxjava
- Ознакомьтесь с его принципами, написав от руки простую версию фреймворка Rxjava.
6.1. Диаграмма классов Uml
6.2 Эффект бега
6.3 Код выглядит следующим образом
- Класс MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
SingleU
.just(111)
.map(object : FunctionU<Int, String> {
override fun apply(t: Int): String {
return "操作符$t"
}
})
.subscribeOn()
.observeOn()
.subscribe(object : ObserverU<String> {
override fun onSubscribe() {
println("触发时机 onSubscribe")
}
override fun onError() {
println("触发时机 onError")
}
override fun onSuccess(t: String) {
println("触发时机 onSuccess $t")
}
})
}
}
- Интерфейс ObservableU
//被观察者的顶层接口
interface ObservableU<T> {
fun subscribe(observer: ObserverU<T>)
}
- Интерфейс ObserverU
//观察者的顶层接口
interface ObserverU<T> {
fun onSubscribe()
fun onSuccess(t: T)
fun onError()
}
- Интерфейс преобразования FunctionU
interface FunctionU<T, R> {
fun apply(t: T): R
}
- Абстрактный класс SingleU
//该类继承自ObservableU,定义了具体被观察者的实现类的公共方法,该类是供外界使用的
abstract class SingleU<T> : ObservableU<T> {
override fun subscribe(observer: ObserverU<T>) {
subscribeActual(observer)
}
protected abstract fun subscribeActual(observer: ObserverU<T>)
fun <R> map(mapper: FunctionU<T, R>): SingleU<R> {
return SingleMapU(this, mapper)
}
fun subscribeOn(): SingleU<T> {
return SingleSubscribeOnU(this)
}
fun observeOn(): SingleU<T> {
return SingleObserveOnU(this)
}
companion object {
fun <T> just(value: T): SingleU<T> {
return SingleJustU(value)
}
}
}
- Класс SingleJustU
class SingleJustU<T>(private val value: T) : SingleU<T>() {
override fun subscribeActual(observer: ObserverU<T>) {
observer.onSubscribe()
observer.onSuccess(value)
}
}
- Класс SingleMapU
class SingleMapU<T, R>(private val source: ObservableU<T>, private val mapper: FunctionU<T, R>) :
SingleU<R>() {
override fun subscribeActual(observer: ObserverU<R>) {
source.subscribe(MapSingleObserverU1(observer, mapper))
}
internal class MapSingleObserverU1<T, R>(
private val t: ObserverU<R>,
private val mapper: FunctionU<T, R>
) : ObserverU<T> {
override fun onSubscribe() {
t.onSubscribe()
}
override fun onSuccess(value: T) {
t.onSuccess(mapper.apply(value))
}
override fun onError() {
t.onError()
}
}
}
- Класс SingleObserveOnU
class SingleObserveOnU<T>(private val sourceU: ObservableU<T>) : SingleU<T>() {
override fun subscribeActual(observer: ObserverU<T>) {
sourceU.subscribe(ObserveOnSingleObserver1(observer))
}
internal class ObserveOnSingleObserver1<T>(private val actual: ObserverU<T>) : ObserverU<T> {
private val handler = Handler(Looper.getMainLooper())
override fun onSubscribe() {
actual.onSubscribe()
}
override fun onSuccess(t: T) {
handler.post { actual.onSuccess(t) }
}
override fun onError() {
handler.post { actual.onError() }
}
}
}
- Класс SingleSubscribeOnU
class SingleSubscribeOnU<T>(private val sourceU: ObservableU<T>) : SingleU<T>() {
override fun subscribeActual(observer: ObserverU<T>) {
executorService.submit(SubscribeOnObserverU1(observer, sourceU))
}
internal class SubscribeOnObserverU1<T>(
private val actual: ObserverU<T>,
private val source: ObservableU<T>
) : ObserverU<T>, Runnable {
override fun onSubscribe() {
actual.onSubscribe()
}
override fun onSuccess(t: T) {
actual.onSuccess(t)
}
override fun onError() {
actual.onError()
}
override fun run() {
source.subscribe(this)
}
}
companion object {
private val executorService = Executors.newCachedThreadPool()
}
}
7. Rxjava в сочетании с Retrofit для инкапсуляции сетевой инфраструктуры.
- адрес проекта
- общие операторы
- карта: получение данных, отправленных из восходящего потока, обработка данных до определенной степени, а затем отправка их в нисходящий поток. Сценарий приложения: он может использоваться для обработки данных и определяет, нужно ли создавать исключение, в соответствии со значением состояния;
- compose: используйте его функции, чтобы уменьшить повторяющийся код, например переключение потоков. Переданный параметр функции является конкретным преобразователем;
- zip: объединить источники данных;
- flatMap: вложенные сетевые запросы;
- Разница между flatMap и compose заключается в том, что оба пользователя меняют наблюдателя. Compose работает со всем потоком наблюдателей, который можно рассматривать как функцию, которая получает наблюдателя и возвращает новый наблюдатель. flatMap используется для преобразования данных, отправляемых наблюдаемым объектом, что можно рассматривать как функцию, которая получает элемент данных и возвращает наблюдаемый объект. Compose хорош для изменения потоков данных, добавления обработки ошибок.
8. Резюме
- В этой статье мы выбрали использование Single для анализа основных принципов Rxjava. В то же время он использует Rxjava3 и Retrofit2 для инкапсуляции в сетевой модуль в конце, предоставляя простой API для внешнего использования (сетевая часть нового проект использует сопрограммы для Jetpack. Библиотека поддержки упакована в сочетании с Retrofit и Flow, и эта часть знаний будет постепенно внедряться в вышеуказанный проект).