美文网首页RxJava手机移动程序开发程序员
抱着陌生的态度再看Rxjava(三)

抱着陌生的态度再看Rxjava(三)

作者: super_shanks | 来源:发表于2017-02-23 13:57 被阅读1396次

本章讲的是操作符,有rxjava1经验的同志们,请继续右转。不对。。。可能都不用继续往下看。。

操作符

什么叫操作符,如果按照直接的个人理解,我会解释给你听,他是将你的Observable或者是Flowable转换成另外一种Observable或者是另外一种Flowable

用我们的上下游分析法,我们把操作符称为中游的拦截者。

我们用伪代码来解释的话就是这样的:

        Flowable/Observable<A>.操作符 = Flowable/Observable<B>

而rxjava2的操作符基本跟rxjava1没有什么太大的出入。我们先来看一个最最基础的

  • map

 不要把这个map跟你理解的map混淆起来,他不是你理解的map
 ```

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

      我们不要去管这个方法是干什么的,从这个方法的传参和返回类型,就可以基本知道他是干什么的。它是把Flowable<T>变成了Flowable<R>。
     这个拦截者在中游拦截到了上游扔下来的一个包袱,打开,把里面的东西T,换成了东西R,扔到下游。

   *  ####flatMap
    ```
@CheckReturnValue
    @SchedulerSupport(SchedulerSupport.NONE)
    public final <R> Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper) {
        return flatMap(mapper, false);
    }

上面的map方法直接是最最纯粹的类型转换,而这个方法则允许你讲获取到类型T,进行再次操作,最后返回一个经过你重新包装的Observable。
这个拦截者比map还要胡来,直接在中游拦截到了上游的包袱,直接整个拿掉,并且把自己的包袱扔到了下游。

  • 还有什么map

由于一下子有了两个map让我们不禁好奇是不是还有一些map,我们在Observable类中,搜索了一下带有map的方法,发现还有两个,一个是concatMap,一个是switchMap。
 我们尝试着在subscribe中发送多个onNext请求,然后对这三种map做一一的处理,并在在最后的subscribe中做接受并打印结果
Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
            }
        }).flatMap(new Function<Integer, ObservableSource<String>>() {
            @Override
            public ObservableSource<String> apply(Integer integer) throws Exception {
                final List<String> list = new ArrayList<>();
                for (int i = 0; i < 3; i++) {
                    list.add("I am value " + integer);
                }
                return Observable.fromIterable(list).delay(10,TimeUnit.MILLISECONDS);
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.d(TAG, s);
            }
        });
 最终打印出来的结果可以看到concatMap是按照顺序的,flatMap和switchMap都是无序。
 那flatMap和switchMap有什么不一样呢,我们看到switchMap方法上有这么一段备注:

emitting the items emitted by the most recently emitted
of these ObservableSources

 说明他接收的是最近的一个数据,那么具体最近的定义事多少呢,我们先不去看具体的相应时间差是多少,我们在map方法中对delay稍作修改
                int delay = 200;
                if (integer > 1)
                    delay = 180;

                return Observable.fromIterable(list).delay(delay, TimeUnit.MILLISECONDS);

对大于1的延迟改为180毫秒,否则延迟是200毫秒,你会发现switchMap只能收到3。

那么我们略微的总结一下,如果你对顺序要求比较高的你就使用concatMap;如果你对顺序是没有要求的,但是不希望错过任何一个请求的,那你就使用flatMap;如果你对同一时间内的请求只需要一个(感觉这种情况会比较少),那就使用switchMap。
  • zip

 很有可能跟你想的是一样的,zip我们都知道是干嘛用的,那么在这边当操作符用的话,你想一想是干嘛用的,如果用我们的上下游分析法来分析的话,这一回中游的拦截者做了什么。
 我们在`Observable`类中搜索zip的方法,发现重载了好多, 我们看到有很多种传参
public static <T1, T2, R> Observable<R> zip(
            ObservableSource<? extends T1> source1, ObservableSource<? extends T2> source2,
            BiFunction<? super T1, ? super T2, ? extends R> zipper) {
        return zipArray(Functions.toFunction(zipper), false, bufferSize(), source1, source2);
    }

我们就来看一下这个方法,传入两个Observable,传出一个Observable。
这一回中游的拦截者做的事情是把上游上两个不同的扔东西的人的东西捆绑在一块儿再往下游扔。
读者可以自行的定义两个Observable,并且调用

Observable.zip(observable1, observable2, new ...)

你做了几番尝试之后,你会通过log发现如下的一些结果
* zip只会打包onNext方法
* 打包渠道中只要有一个渠道触发了onComplete方法,那么就会停止继续打包。

  • zip有什么用

 我们平时有没有过一种情况,有两个网络请求,我们需要等着两个网络请求都收到结果之后再做下一步的操作。
 那么在没有使用rxjava之前我们是这样做的:
 ```

httpRequest1.request();
httpRequest2.request();

onRequest1(){
    request1 = true;
    goNext();
}

onRequest2(){
    request2 = true;
    goNext();
}

goNext(){
    if(request1 && request2){
        //TODO
    }
}
我就问你,难不难受。。。。
   如果使用zip操作符,你根本就不用去管这两个东西谁先来谁后来什么的,只要你出发了onNext那我就可以直接catch到你,并且把你打包了。由于我们使用的网络请求的例子。你如果自己去通过HttpUrlConnection实现,这里推荐使用Retrofit,直接继承了Rxjava,可谓是当前最好用的网络请求框架。
    Observable<Response1> observable1 =
            api.getRespones1(new Request1()).subscribeOn(Schedulers.io());

    Observable<Response2> observable2 =
            api.getRespones2(new Request2()).subscribeOn(Schedulers.io());

    Observable.zip(observable1, observable2,
            new BiFunction<Response1, Response2, YourObject>() {
                @Override
                public YourObject apply(Response1 baseInfo,
                                      Response2 extraInfo) throws Exception {
                    //do something
                    return new YourObject(baseInfo, extraInfo);
                }
            }).observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Consumer<YourObject>() {
                @Override
                public void accept(YourObject userInfo) throws Exception {
                    //do something;                                                           
                }
            });
    而具体的Retrofit的使用姿势,大家可以先去查阅相应的文档,我不确定之后会不会再来写一下。

   *  ##filter
    这个操作符的作用,就跟他字面意思一样,筛选。
    我们直接用了看看
    ```
 Flowable<Integer> flowable = Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> e) throws Exception {
                for(int i = 0; i < 400; i++){
                    Thread.sleep(100);
                    Log.e("subscribe", "i  :   " + i);
                    e.onNext(i);
                }
            }
        }, BackpressureStrategy.ERROR).filter(new Predicate<Integer>() {
            @Override
            public boolean test(@NonNull Integer integer) throws Exception {
                return integer > 300;
            }
        });
然后你把这个flowable订阅一下,你会发现他只会输出大于300的onNext,也就是说会把你的onNext携带的请求对象进行筛选,只取你需要的请求。
  • sample

 取样操作符
public final Flowable<T> sample(long period, TimeUnit unit) {
        return sample(period, unit, Schedulers.computation());
    }
每隔一段时间,取一个样本。当然他还有一些重载的方法,都比较简单,再次不一一列出。
  • compose

 这个厉害了,我们平时在书写我们的Flowable或者是Observable的时候,一直都会喜欢做一些额外的操作,比如说observerOn,比如说subscribeOn。
为了不每一次都这么来On一下。我们是否想一想通过什么方式把这些东西抽出来,对其进行重用。
这个时候我们需要使用compose操作符
```

observable2.compose(new ObservableTransformer<String, String>() {
@Override
public ObservableSource<String> apply(Observable<String> upstream) {
return upstream.subscribeOn(Schedulers.io());;
}
});
flowable.compose(new FlowableTransformer<Integer, Integer>() {
@Override
public Publisher<Integer> apply(Flowable<Integer> upstream) {
return upstream.subscribeOn(Schedulers.io());
}
})

   我们可以看到observable和flowable的compose方法的传参有所不同,rxjava2,特地为两者各自准备了他们自己的Transformer(估计是为了考虑到背压的问题),因此我们拿一个具体的Transformer出来讲:

public interface ObservableTransformer<Upstream, Downstream> {
/**
* Applies a function to the upstream Observable and returns an ObservableSource with
* optionally different element type.
* @param upstream the upstream Observable instance
* @return the transformed ObservableSource instance
*/
ObservableSource<Downstream> apply(Observable<Upstream> upstream);
}

    我们只需要虚自定义一个我们自己的transformer实现ObservableTransformer接口即可。

    * 和flatMap有什么不一样么
      一个是吧Observable<T>转成Observable<R>,一个是把T转成Observable<R>。
      也就是说compose操作符是把整个的上游给换了一个新的Observable,所有的都按照我的来;而flatMap是你来一个请求我给你包装成一个新的Observable,细一看区别还是很明显的。


   *  ##后续操作符留坑
      TBC...

-------

##电梯
  [抱着陌生的态度再看Rxjava(一)](http://www.jianshu.com/p/fbfdd6fa6154)   
  [抱着陌生的态度再看Rxjava(二)](http://www.jianshu.com/p/96df60fd35c6)
    [抱着陌生的态度再看Rxjava(四)](http://www.jianshu.com/p/de8af3fadede)

相关文章

  • 抱着陌生的态度再看Rxjava(三)

    本章讲的是操作符,有rxjava1经验的同志们,请继续右转。不对。。。可能都不用继续往下看。。 操作符 什么叫操作...

  • 抱着陌生的态度再看Rxjava(一)

    把它当做陌生人再一次去认识 环境集成 首先废话不多说,先把Rxjava集成到我们项目中来。 rxjava1和rxj...

  • 抱着陌生的态度再看Rxjava(二)

    如果你已经有了Rxjava1的使用基础,你可以看一下这一篇的大体的提纲,了解就可以链接到三,说不定三都不用看。。如...

  • 抱着陌生的态度再看Rxjava(四)

    了解背压的看管请继续右转您内,请一定看最末,你会发现你其他地方没见过的东西。 背压二三事 不知大家还记不记得在看(...

  • 抱着微笑的态度

    1.经历了胖胖和瘦瘦 去年五月我开始接触培伟推荐的森米。为我和减肥斗争多年的肥肉开启了新的人生。经历了大半年的努力...

  • 抱着感恩的态度

    人应该尽可能把自己的获得,理解成幸运;却应该尽可能的把他人的获得,理解成努力。 “我所拥有的,是因为我的一点点努力...

  • RXJava Observable详解 (RXJava Part

    目录更新~RXJava Part 2 Subject当然先看完本篇文章再看第二篇吧 使用RXJava实现观察者模式...

  • 抱着请教别人的态度

    曾在一本书上读到这样一句话,书的作者我已经忘记了。他写道“人类是不是有一种喜欢指点别人的本能呢?”确实,人类有要学...

  • 抱着离婚的态度结婚

    结婚是人生中一件很重要的事,也是很甜蜜的一件事,毕竟是要跟自己选择的另一半度过下半生的,可是身边居然有人是抱着离婚...

  • RxJava 2 源码解析之线程切换

    在分析RxJava2的线程切换源码之前,再看看在上一篇RxJava 2 源码解析之创建-订阅-变换-发布里总结的流...

网友评论

    本文标题:抱着陌生的态度再看Rxjava(三)

    本文链接:https://www.haomeiwen.com/subject/mtwmwttx.html