×

RxJava 学习笔记 (二)

96
疼蛋之丸
2017.12.15 00:30* 字数 2508

作者: 一字马胡
转载标志 【2017-12-15】

更新日志

日期 更新内容 备注
2017-12-15 RxJava学习笔记系列 系列笔记 (二)
2017-12-15 RxJava 学习笔记 (一) 增加系列笔记一
2017-12-15 21:36 考虑到RxJava很大程度上用于android开发中,而我自身不是移动开发者,所以暂时将RxJava学习笔记系列挂起,在未来需要使用RxJava的时候再继续学习,并且结合实际的应用来学习会收获更多 挂起

导入

在RxJava学习笔记系列的第一篇文章中,我分析了RxJava中核心的两个对象Observable和Observer,并且分析了Observer是如何实现订阅一个Observable的,作为学习RxJava的第一篇分析总结,内容较为浅显,本文将接着RxJava 学习笔记 (一),重点在于学习RxJava的Observable提供的丰富的数据流聚合操作api。

在学习RxJava Observable的聚合操作之前,可以结合java 8中的Stream API来学习,可以参考Java Streams API,两者之间是互通的。

介于RxJava提供了大量的聚合操作api,本文将挑选其中几个比较有代表性的api进行分析总结,其余的api可以参考RxJava的源代码,以及结合自身实践来学习。

count

count操作用来获取Observable在触发onComplete的时候一共发送了多少个数据项,具体可以看下面的解释:


Returns a Single that counts the total number of items
emitted by the source ObservableSource and emits this
count as a 64-bit Long.


下面是一个使用count操作的例子:


        Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                e.onNext("test1");
                e.onNext("test2");
                e.onComplete();
            }
        });

        observable.subscribe(new Consumer<String>() {
            public void accept(String s) throws Exception {
                System.out.println("->" + s);
            }
        });

        observable.count().subscribe(new Consumer<Long>() {
            public void accept(Long aLong) throws Exception {
                System.out.println("total emit:" + aLong);
            }
        });

最后count的输出是2,也就是说Observable在触发onComplete的时候一共发送了2个数据,需要注意的是,我们在完成发送数据之后需要及时调用Observer的onComplete方法来告诉Observer上游的Observable已经完成发送数据了,Observable在调用了Observer的onComplete方法之后,再调用onNext方法就发送不出去了,为什么呢?除了调用onComplete来结束Observer再接收到Observable的事件之外,调用onError也是同样的效果,下面就来分析一下为什么会这样。

在上面的代码中,我们的Observable是通过调用Observable的静态方法create来创建的,来具体看一下create的实现:


    public static <T> Observable<T> create(ObservableOnSubscribe<T> source) {
        ObjectHelper.requireNonNull(source, "source is null");
        return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source));
    }

关于Observable和Observer是如何联系起来的,可以参考第一篇文章RxJava 学习笔记 (一),下面来看一下ObservableCreate类中是如何来调用Observer的onNext方法的,也就是来看看到底为什么Observable在调用了Observer的onComplete之后再调用onNext方法就不管用了,主要来看ObservableCreate类里面的CreateEmitter类的onNext方法,因为在ObservableCreate里面,Observer被转换为了CreateEmitter:

        @Override
        public void onNext(T t) {
            if (t == null) {
                onError(new NullPointerException("onNext called with null. Null values 
                are generally not allowed in 2.x operators and sources."));
                return;
            }
            if (!isDisposed()) {
                observer.onNext(t);
            }
        }

首先判断了一下需要发送的事件是否为null,如果为null则直接抛出异常,否则会调用一个方法isDisposed来哦按段是否能调用实际的Observer的onNext方法,下面是isDisposed方法的具体实现细节:


  @Override
  public boolean isDisposed() {
       return DisposableHelper.isDisposed(get());
  }

    /**
     * Checks if the given Disposable is the common {@link #DISPOSED} enum value.
     * @param d the disposable to check
     * @return true if d is {@link #DISPOSED}
     */
    public static boolean isDisposed(Disposable d) {
        return d == DISPOSED;
    }        
        

Disposable在RxJava中是一个重要的对象,它可以用来取消订阅关系,并且支持查询是否已经取消订阅的状态,isDisposed方法最终需要判断当前Observer的Disposable是否等于DISPOSED,如果是,那么就是出于已经取消订阅的状态,那么就不需要继续调用Observer的onNext方法来传播事件了,否则继续调用,那么这个状态是在哪里更新的呢?可以在onComplete和onError中看到状态的更新:

首先来看onError:


        public void onError(Throwable t) {
            if (!tryOnError(t)) {
                RxJavaPlugins.onError(t);
            }
        }

        public boolean tryOnError(Throwable t) {
            if (t == null) {
                t = new NullPointerException("onError called with null. Null 
                values are generally not allowed in 2.x operators and sources.");
            }
            if (!isDisposed()) {
                try {
                    observer.onError(t);
                } finally {
                    dispose();
                }
                return true;
            }
            return false;
        }

其中重点在于dispose方法:


        @Override
        public void dispose() {
            DisposableHelper.dispose(this);
        }

    /**
     * Atomically disposes the Disposable in the field if not already disposed.
     * @param field the target field
     * @return true if the current thread managed to dispose the Disposable
     */
    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;
    }

可以看到,Observer的Disposable就是在dispose方法里面被更新为DISPOSED的。下面再来看onComplete:


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

可以看到,也会调用dispose方法来更新Observer的Dispose的状态。

first/last

使用first/last操作可以获取Observable发送给Observer的第一个事件和最后一个事件,下面是简单的使用示例:


        Observable.create(new ObservableOnSubscribe<String>() {
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                e.onNext("test1");
                e.onNext("test2");
                e.onComplete();
            }
        })./*first("default")*/last("default").subscribe(new Consumer<String>() {
            public void accept(String s) throws Exception {
                System.out.println(s);
            }
        });

下面来简单分析一下first/last的实现原理,为了不赘述,拿last的实现来分析,last的方法实现细节如下:


    public final Single<T> last(T defaultItem) {
        ObjectHelper.requireNonNull(defaultItem, "defaultItem is null");
        return RxJavaPlugins.onAssembly(new ObservableLastSingle<T>(this, defaultItem));
    }

该方法会返回一个ObservableLastSingle对象,ObservableLastSingle是一种特殊的Observable,它只能发射一条数据。并且继续跟进看会发现订阅该Observable的Observer会被包装成一个LastObserver。神奇的地方在于,SingleObserver没有onNext,所以LastObserver每次调用onNext都会记录下事件,当LastObserver调用了onComplete方法的时候,下面的代码展示了具体的实现细节:


        @Override
        public void onComplete() {
            s = DisposableHelper.DISPOSED;
            T v = item;
            if (v != null) {
                item = null;
                actual.onSuccess(v);
            } else {
                v = defaultItem;
                if (v != null) {
                    actual.onSuccess(v);
                } else {
                    actual.onError(new NoSuchElementException());
                }
            }
        }

actual就是last之后的Observer,所以这里可以看出来,会将Observable的最后一个事件通过onSuccess来告诉Observer。first的分析类似就不再赘述了。

map

map操作可以对Observable的每个事件进行转换,转换成一个其他的事件,再通知到Observer,下面是一个简单的使用map的示例:


        Observable.create(new ObservableOnSubscribe<String>() {
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                e.onNext("test1");
                e.onNext("1001");
                e.onComplete();
            }
        }).map(new Function<String, Integer>() {
            public Integer apply(String s) throws Exception {
                try {
                    return Integer.parseInt(s);
                } catch (NumberFormatException nbe) {
                    return 0;
                }
            }
        }).subscribe(new Consumer<Integer>() {
            public void accept(Integer integer) throws Exception {
                System.out.println("->" + integer);
            }
        });

我们是提供了一个Function来进行转换的,在上面的例子中实现的是将String类型的事件转换为Integer类型的事件,具体的实现还是比较简单的:


    public final <R> Observable<R> map(Function<? super T, ? extends R> mapper) {
        ObjectHelper.requireNonNull(mapper, "mapper is null");
        return RxJavaPlugins.onAssembly(new ObservableMap<T, R>(this, mapper));
    }

可以看到,调用map操作涉及到一个新的包装类ObservableMap,在ObservableMap内部进行Observer绑定的时候,细节代码如下:


    @Override
    public void subscribeActual(Observer<? super U> t) {
        source.subscribe(new MapObserver<T, U>(t, function));
    }

又出现了一个包装类MapObserver,并且将Observer和mapper function都包装起来了,来看一个MapObserver的onNext的实现细节:


        @Override
        public void onNext(T t) {
            if (done) {
                return;
            }
            if (sourceMode != NONE) {
                actual.onNext(null);
                return;
            }
            U v;
            try {
                v = ObjectHelper.requireNonNull(mapper.apply(t), "The mapper
                 function returned a null value.");
            } catch (Throwable ex) {
                fail(ex);
                return;
            }
            actual.onNext(v);
        }

可以看到,在进行Observer的onNext调用之前,会首先调用mapper.apply来进行事件转换,然后再将转换结果发送出去,很好理解。其他操作也可以根据这套逻辑进行分析,就不再赘述。

flatMap

flatMap和map类似,但是map是将单个事件进行转换,变成一个其他的事件,本质上还是事件,但是flatMap会将单个事件铺开成一个新的Observable,下面是一个使用flatMap的简单示例:


       Observable.create(new ObservableOnSubscribe<String>() {
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                e.onNext("test1");
                e.onNext("1001");
                e.onComplete();
            }
        }).flatMap(new Function<String, ObservableSource<Integer>>() {
            public ObservableSource<Integer> apply(final String s) throws Exception {
                return Observable.create(new ObservableOnSubscribe<Integer>() {
                    public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                        int result = 0;
                        try {
                            result = Integer.parseInt(s);
                        } catch (NumberFormatException nfe) {
                            result = 0;
                        }
                        e.onNext(result);
                        e.onComplete();
                    }
                });
            }
        }).subscribe(new Consumer<Integer>() {
            public void accept(Integer integer) throws Exception {
                System.out.println("->" + integer);
            }
        });

介于flatMap的分析有些繁琐,就不再此进行描述了,对于flatMap实现原理的分析,可以参考前面的map的分析,但是flatMap的实现确实比起map要复杂得多,下面给出onNext的分析路径,可以参考下面的路径来分析flatMap的具体实现:


1:
Observable:public final <R> Observable<R> flatMap(Function<? super T,
 ? extends ObservableSource<? extends R>> mapper, boolean delayErrors,
  int maxConcurrency, int bufferSize)

2:
ObservableFlatMap:ublic void subscribeActual(Observer<? super U> t)            

3:
MergeObserver:public void onNext(T t)
    ->void subscribeInner(ObservableSource<? extends U> p)
         ->void tryEmitScalar(Callable<? extends U> value)
              "actual.onNext(u);"

            

filter

filter操作可以过滤调一些不需要的事件,Observer可以订阅自己关心的事件,下面是一个使用filter的简单示例:


        Observable.create(new ObservableOnSubscribe<String>() {
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                e.onNext("test1");
                e.onNext("1001");
                e.onComplete();
            }
        }).filter(new Predicate<String>() {
            public boolean test(String s) throws Exception {
                return s.length() > 4;
            }
        }).subscribe(new Consumer<String>() {
            public void accept(String s) throws Exception {
                System.out.println("->" + s);
            }
        });

关于filter的具体实现原理,参考map的实现,模式是一模一样的,只是map将一个事件转换为另外一个事件,而filter会对每个事件调用test方法来进行测试是否为Observer感兴趣,如果感兴趣则会返回true,那么该事件就可以通知到下游Observer,否则就是下游Observer不感兴趣的事件,就不会被通知到下游Observer。

reduce

reduce可以将多个事件合并为一个事件,一个比较形象的例子是,上游Observable发射一批整形数据,然后使用reduce操作进行求和操作,下游Observer就可以取到所有数的和,下面是一个简单的实现:


        Observable.create(new ObservableOnSubscribe<Integer>() {
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                for (int i = 0;i < 10; i ++) {
                    e.onNext(i);
                }
                e.onComplete();
            }
        }).reduce(new BiFunction<Integer, Integer, Integer>() {
            public Integer apply(Integer integer, Integer integer2) throws Exception {
                return integer + integer2;
            }
        }).subscribe(new Consumer<Integer>() {
            public void accept(Integer integer) throws Exception {
                System.out.println("sum:" + integer);
            }
        });

当然还可以使用reduce来求最大最小值,以及一些其他的具有比较性质、累计性质的操作。reduce的实现原理可以结合last和map的分析来理解,再次不再赘述。

toList/toMap

你可以将Observable发送的事件直接转换为一个list,或者是一个map,下面是使用toList的简单示例:



        Observable.create(new ObservableOnSubscribe<Integer>() {
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                for (int i = 0;i < 10; i ++) {
                    e.onNext(i);
                }
                e.onComplete();
            }
        }).toList().subscribe(new Consumer<List<Integer>>() {
            public void accept(List<Integer> integers) throws Exception {
                integers.forEach(new java.util.function.Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) {
                        System.out.print(integer + " ");
                    }
                });
            }
        });

下面来分析一下toList的具体实现:


    public final Single<List<T>> toList(final int capacityHint) {
        ObjectHelper.verifyPositive(capacityHint, "capacityHint");
        return RxJavaPlugins.onAssembly(new ObservableToListSingle<T, List<T>>(this, capacityHint));
    }

可以看到toList返回的是一个ObservableToListSingle类型的Observable,来看一下ObservableToListSingle里面的subscribeActual方法的具体实现(至于为什么要看这个方法,可以参考系列文章的第一篇):


    @Override
    public void subscribeActual(SingleObserver<? super U> t) {
        U coll;
        try {
            coll = ObjectHelper.requireNonNull(collectionSupplier.call(), "The
             collectionSupplier returned a null collection. Null values are
              generally not allowed in 2.x operators and sources.");
        } catch (Throwable e) {
            Exceptions.throwIfFatal(e);
            EmptyDisposable.error(e, t);
            return;
        }
        source.subscribe(new ToListObserver<T, U>(t, coll));
    }

可以看到将Observer转换为了一个ToListObserver,下面来看一下我们比较关系的onNext方法的实现:


        @Override
        public void onNext(T t) {
            collection.add(t);
        }


看起来onNext的作用就是拦截Observable的事件,然后保存起来,那猜测应该会在onComplete的时候将这个List发送给下游Observe,下面来看一下onComplete的具体实现:


        @Override
        public void onComplete() {
            U c = collection;
            collection = null;
            actual.onSuccess(c);
        }


和猜测的一样,toMap操作的分析类似于toList,并且我们可以猜测toMap操作需要我们提供一个转换function,然后toMap会在实际实现中和toList一样拦截上游Observable的事件,然后调用我们提供的function来进行转换为一个Map的Entry,最后在onComplete的时候将整个map发送到下游Observer,具体的分析就不再此赘述了。

groupBy

下面来分析最后一个操作groupBy,也就是分组,可以对Observable的事件进行分组,然后按照组别来将事件组传递到下游Observer中去,下面是一个简单的使用groupBy的例子:


              Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                e.onNext("hujian1");
                e.onNext("hujian2");
                e.onNext("libai1");
                e.onNext("libai2");

                e.onComplete();
            }
        }).groupBy(new Function<String, String>() {
            @Override
            public String apply(String s) throws Exception {
                return s.substring(0, s.length() - 1);
            }
        }).subscribe(new Consumer<GroupedObservable<String, String>>() {
            @Override
            public void accept(GroupedObservable<String, String> stringStringGroupedObservable) throws Exception {
                System.out.println("group key:" + stringStringGroupedObservable.getKey());

                stringStringGroupedObservable.subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {
                        System.out.println(s);
                    }
                });
            }
        });

下面来看一下groupBy的关键实现代码:


    @Override
    public void subscribeActual(Observer<? super GroupedObservable<K, V>> t) {
        source.subscribe(new GroupByObserver<T, K, V>(t, keySelector, valueSelector,
         bufferSize, delayError));
    }


        @Override
        public void onNext(T t) {
            K key;
            try {
                key = keySelector.apply(t);
            } catch (Throwable e) {
                Exceptions.throwIfFatal(e);
                s.dispose();
                onError(e);
                return;
            }

            Object mapKey = key != null ? key : NULL_KEY;
            GroupedUnicast<K, V> group = groups.get(mapKey);
            if (group == null) {
                // if the main has been cancelled, stop creating groups
                // and skip this value
                if (cancelled.get()) {
                    return;
                }

                group = GroupedUnicast.createWith(key, bufferSize, this, delayError);
                groups.put(mapKey, group);

                getAndIncrement();

                actual.onNext(group);
            }

            V v;
            try {
                v = ObjectHelper.requireNonNull(valueSelector.apply(t), 
                "The value supplied is null");
            } catch (Throwable e) {
                Exceptions.throwIfFatal(e);
                s.dispose();
                onError(e);
                return;
            }

            group.onNext(v);
        }

实现的就是按照我们的keySelect来进行分组的功能,可以从onNext的实现中发现,groupBy在发现一个新的key的时候就会调用下游Observer的onNext,而不是等Observable所有事件发送结束后再一次性发送结果,这一点需要特别注意。

本文到此就结束了,文章介绍了几个较为典型的RxJava Observable提供的聚合操作,并且每个操作都有例子进行分析,以及每一个操作的具体实现细节的分析总结,当然RxJava中Observable提供的聚合操作时非常丰富的,本文提到的只是冰山一角,其他的操作还需要自己多进行实践总结。

注:文章中的图片参考:projectreactor.io

扫码入群
java技术积累
Web note ad 1