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

本章讲的是操作符,有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)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,829评论 1 331
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,603评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,846评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,600评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,780评论 3 272
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,695评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,136评论 2 293
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,862评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,453评论 0 229
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,942评论 2 233
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,347评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,790评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,293评论 3 221
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,839评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,448评论 0 181
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,564评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,623评论 2 249

推荐阅读更多精彩内容