RxJava实现原理分析part2-数据处理

先来一个Jack大神的演讲视频
Managing the Reactive World with RxJava

Backpressue

Backpressue是指一个Flowable管道处理中,有些异步状态无法及时处理产出的值,需要一种方式来告诉upstream降低生产数据的节奏,本质上是一种flow control策略

如下例子,source产出了过多的数据,会导致downstream处理不及时而导致问题

    PublishProcessor<Integer> source = PublishProcessor.create();

    source
    .observeOn(Schedulers.computation())
    .subscribe(v -> compute(v), Throwable::printStackTrace);

    for (int i = 0; i < 1_000_000; i++) {
        source.onNext(i);
    }

    Thread.sleep(10_000); 

使用如下写法,则不会有任何问题

Flowable.range(1, 1_000_000)
.observeOn(Schedulers.computation())
.subscribe(v -> compute(v), Throwable::printStackTrace);

Thread.sleep(10_000); 

在Rxjava3里面,提供了5种处理策略,定义在BackpressureStrategy里面

  • MISSING onNext事件没有任何buffer缓存,或丢弃,downstream必须处理这些overflow.适用场景:
  • ERROR 发送一个MissingBackpressureException以防止downstream无法继续处理
  • BUFFER 缓存所有onNext值到downstream消费,默认Buffer大小是128,可以修改
  • DROP 如果downstream无法处理,丢弃最近的onNext事件
  • LATEST 仅保存最新的onNext值,如果downstream无法处理,则覆写先前的值

具体实现的类图结构如下:
在这里插入图片描述

onBackpressureXXX操作

大部分开发者遇到backpressure是当应用出问题抛出MissingBackpressureException异常,而且异常通常指向于observeOn操作上。

实际的原因是使用了不支持backpressure的PublishProcessor、timer()、interval、或者通过create自定义的操作

有几种方式可以处理此场景:

  • 增加buffer的大小

有时overflow是因为快速的事件产生。用户突然快速点击屏幕,observeOn在android默认大小是16

在最新的Rxjava里面,开发者可以显式的指定缓存大小,相关的参数

    Flowable.range(1, 1_000_000)
              .onBackpressureBuffer(1024)

然而在通常场景下,只设置一个临时的大小也会出现overflow的情况,当源数据生产了超出预测缓存大小时,在这种场景下,可以使用如下操作

  • onBackPressureBuffer系列方法

传入的参数都不同,最终都是创建FlowableOnBackpressureBuffer

  • final int bufferSize 缓存大小
  • final boolean unbounded 如果为true,表示缓存大小被解释为内部无界缓存的island值
  • final boolean delayError 如果为true,表示一个Flowable里面的exception会延迟发送,直到缓存里面的所有元素都被downstream消费掉;为false时,会直接将Excetion通知到downstream,忽略缓存的数据
  • final Action onOverflow 当一个事件需要被缓存,但是没有空间的时候,会执行此aciton

其中unbounded生效的场景为

if (unbounded) {
    q = new SpscLinkedArrayQueue<>(bufferSize);  // 可以调整大小
} else {
    q = new SpscArrayQueue<>(bufferSize);  // 大小固定
}
  • onBackPressureDrop

如果downstream还没有准备好接收新的事件(通过Subscription.request调用的缺失来表示);从当前Flowable里面丢弃.

如果downstream request为0,则由此产生的Flowable将不调用onNext,直到Subscriber再次调用request(n)来增加请求计数。

参数Consumer<? super T> onDrop 表示针对每个drop的事件,都会执行此action,应该快速且非阻塞

对应的实现策略在FlowableOnBackpressureDrop文件里面

  • onBackpressureLatest

如果downstream还没有准备好接收新的事件(通过Subscription.request调用的缺失来表示);从当前Flowable里面丢弃除最新之外的事件,当downstream准备好的时候,把最新的事件发给downstream

具体的实现是在FlowableOnBackpressureLatest类里面

backpressured 数据源的创建方式
  • **Flowable.just **

返回一个Flowable,然后把给定的常量引用事件发送出去,然后结束。注意这个事件被获取,然后重新发送,just不会改这个事件。使用fromCallable近需来生成单个事件

一个简单的例子:

    Flowable.just(5).subscribe(new DisposableSubscriber<Integer>() {
        @Override
        public void onStart() {
            request(2);
        }

        @Override
        public void onNext(Integer v) {
            System.out.println(v);
        }
       
        @Override
        public void onError(Throwable t) {

        }
        
        @Override
        public void onComplete() {
            System.out.println("onComplete");
        }
    }

输出为如下,request里面的数字没有影响到onComplete的调用:

5
onComplete

具体实现类为FlowableJust

@Override
public void request(long n) {
    // n 要求大于等于0
    if (!SubscriptionHelper.validate(n)) {
        return;
    }
    if (compareAndSet(NO_REQUEST, REQUESTED)) {
        Subscriber<? super T> s = subscriber;
        // 把事件发送给订阅者
        s.onNext(value);
        if (get() != CANCELLED) {
            // 发送完成事件
            s.onComplete();
        }
    }
}

当just方法里面有多个参数的时候,内部实现是通过formarray

    public static <@NonNull T> Flowable<T> just(T item1, T item2) {
        Objects.requireNonNull(item1, "item1 is null");
        Objects.requireNonNull(item2, "item2 is null");

        return fromArray(item1, item2);
    }
  • Flowable.fromCallable

返回一个Flowable,当一个Subscriber订阅的时候,会调用指定的Callable,然后返回Callable的执行结果并作为事件发送出去

此方法可以指定直到一个Subscriber订阅Publisher时,才执行特定的方法,换句话说,可以延迟加载

Flowable<Integer> o = Flowable.fromCallable(() -> computeValue());

具体实现类为FlowableFromCallable

public void subscribeActual(Subscriber<? super T> s) {
    DeferredScalarSubscription<T> deferred = new DeferredScalarSubscription<>(s);
    s.onSubscribe(deferred);

    T t;
    try {
        // 执行callable.call方法
        t = Objects.requireNonNull(callable.call(), "The callable returned a null value");
    } catch (Throwable ex) {
        Exceptions.throwIfFatal(ex);
        if (deferred.isCancelled()) {
            RxJavaPlugins.onError(ex);
        } else {
            s.onError(ex);
        }
        return;
    }
    // 将执行结果发送出去
    deferred.complete(t);
}

public final void complete(T v) {
    int state = get();
    for (;;) {
        if (state == FUSED_EMPTY) {
            value = v;
            lazySet(FUSED_READY);

            Subscriber<? super T> a = downstream;
            // 把事件发送给订阅者
            a.onNext(v);
            if (get() != CANCELLED) {
                // 发送完成事件
                a.onComplete();
            }
            return;
        }

        // if state is >= CANCELLED or bit zero is set (*_HAS_VALUE) case, return
        if ((state & ~HAS_REQUEST_NO_VALUE) != 0) {
            return;
        }

        if (state == HAS_REQUEST_NO_VALUE) {
            lazySet(HAS_REQUEST_HAS_VALUE);
            Subscriber<? super T> a = downstream;
            a.onNext(v);
            if (get() != CANCELLED) {
                a.onComplete();
            }
            return;
        }
        value = v;
        if (compareAndSet(NO_REQUEST_NO_VALUE, NO_REQUEST_HAS_VALUE)) {
            return;
        }
        state = get();
        if (state == CANCELLED) {
            value = null;
            return;
        }
    }
}
  • Flowable.fromArray

把一个数组转换成一个Publisher,然后发送数组里面的每个元素,当数组长度为1时,等效于just方法

    public static <@NonNull T> Flowable<T> fromArray(@NonNull T... items) {
        Objects.requireNonNull(items, "items is null");
        if (items.length == 0) {
            return empty();
        }
        if (items.length == 1) {
            return just(items[0]);
        }
        return RxJavaPlugins.onAssembly(new FlowableFromArray<>(items));
    }

一个简单的例子

Flowable.fromArray(1, 2, 3, 4, 5).subscribe(System.out::println);

具体实现类为FlowableFromArray

public final void request(long n) {
    if (SubscriptionHelper.validate(n)) {
        if (BackpressureHelper.add(this, n) == 0L) {
            if (n == Long.MAX_VALUE) {
                fastPath();
            } else {
                slowPath(n);
            }
        }
    }
}

void slowPath(long r) {
    long e = 0;
    T[] arr = array;
    int f = arr.length;
    int i = index;
    Subscriber<? super T> a = downstream;

    for (;;) {

        while (e != r && i != f) {
            if (cancelled) {
                return;
            }

            T t = arr[i];

            if (t == null) {
                a.onError(new NullPointerException("The element at index " + i + " is null"));
                return;
            } else {
                // 循环发送事件给downstream
                a.onNext(t);
            }

            e++;
            i++;
        }

        if (i == f) {
            if (!cancelled) {
                // 数组事件都发送完后,
                a.onComplete();
            }
            return;
        }

        r = get();
        if (e == r) {
            index = i;
            r = addAndGet(-e);
            if (r == 0L) {
                return;
            }
            e = 0L;
        }
    }
}

fromIterable 实现fromarrsy类似,FlowableFromIterable可以用来实现状态机

    Iterable<Integer> iterable = () -> new Iterator<Integer>() {
        @Override
        public boolean hasNext() {
            return true;
        }

        @Override
        public Integer next() {
            return 1;
        }
    };

    Flowable.fromIterable(iterable).take(5).subscribe(System.out::println);
  • Flowable.generate

有时,数据源是同步的(blocking)和push的方式,被转换成响应式时,我们调用get或read方法来获取下数据源中的下一块。当然,可以使用Iterable,但是当源和某些资源关联时,当downstream在资源关闭前停止订阅的时, 可能会导致资源泄露

在RxJava里面,处理这些场景,提供了generate工厂方法族

通常,generate使用3个callback

  • 第一个callback 使用Supplier为每个Subscriber创建一个初始化状态
  • 第二个callback 获取state对象,然后提供一个输出Observer,onXXX方法可以被调用来发送事件。这个回调会执行downstream的request,最多只能调用onNext一次,可选后跟onError或onComplete
  • 第三个callable,处理downstream,即当前generator结束序列或被取消时,Consumer来处理后续的

方法的定义如下:

     * @param initialState the {@link Supplier} to generate the initial state for each {@code Subscriber}
     * @param generator the {@link Consumer} called with the current state whenever a particular downstream {@code Subscriber} has
     * requested a value. The callback then should call {@code onNext}, {@code onError} or
     * {@code onComplete} to signal a value or a terminal event. Signaling multiple {@code onNext}
     * in a call will make the operator signal {@link IllegalStateException}.
     * @param disposeState the {@code Consumer} that is called with the current state when the generator
     * terminates the sequence or it gets canceled

    public static <T, S> Flowable<T> generate(@NonNull Supplier<S> initialState, @NonNull BiConsumer<S, Emitter<T>> generator,
            @NonNull Consumer<? super S> disposeState) {
        Objects.requireNonNull(generator, "generator is null");
        return generate(initialState, FlowableInternalHelper.simpleBiGenerator(generator), disposeState);
    }

unsubscribe事件或前一个callback的结束事件,可以在这个里面释放资源

一个简单的例子

     Flowable<Integer> o = Flowable.generate(
         () -> new FileInputStream("data.bin"),
         (inputstream, output) -> {
             try {
                 int abyte = inputstream.read();
                 if (abyte < 0) {
                     output.onComplete();
                 } else {
                     output.onNext(abyte);
                 }
             } catch (IOException ex) {
                 output.onError(ex);
             }
             return inputstream;
         },
         inputstream -> {
             try {
                 inputstream.close();
             } catch (IOException ex) {
                 RxJavaPlugins.onError(ex);
             }
         } 
    );

对应的实现类是FlowableGenerate

从JVM和lib库里面很多方法调用,会跑出checked exception,需要用try/catch包起来,此类中的函数接口不支持抛出checked exception

  • Flowable.create(emitter)
    有时,数据源被封装成Flowable的时候,里面的API不支持backpressure(如异步网络请求)。Rxjava里面提供了create(emitter)工厂方法,包含2个参数
  • 一个callback,该回调将针对每个传入的subscriber调用Emitter接口
  • 一个BackpressureStrategy策略,同onBackpressureXXX类似

当前不支持非BackpressureStrategy之外的策略

Emitter使用起来很简单,直接调用其onNext/onError/onComplete

具体的实现类是FlowableCreate ,看一个简单的例子

        Flowable<String> flowable = Flowable.create(new FlowableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull FlowableEmitter<String> emitter) throws Throwable {
                System.out.println("Publisher subscribe = " + Thread.currentThread().getName());
                emitter.onNext("Hello");
                emitter.onNext("World");
                emitter.onComplete();
            }
        }, BackpressureStrategy.BUFFER);

具体的调用过程,在RxJava分析系列之RxJava实现原理分析part1 里面的

2.观察者模式的实现

数据支持的操作

创建方式

  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/Creating-Observables.md
  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/Phantom-Operators.md
  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/Subject.md
  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/String-Observables.md

支持的操作

  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/Conditional-and-Boolean-Operators.md
  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/Filtering-Observables.md
  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/Connectable-Observable-Operators.md
  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/Combining-Observables.md
  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/Mathematical-and-Aggregate-Operators.md
  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/Blocking-Observable-Operators.md
  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/Operator-Matrix.md
  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/Parallel-flows.md
  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/Async-Operators.md
  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/Observable-Utility-Operators.md

错误处理

  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/Error-Handling-Operators.md
  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/Error-Handling.md

自定义操作

  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/Implementing-Your-Own-Operators.md
  • https://github.com/ReactiveX/RxJava/blob/3.x/docs/Plugins.md
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值