RxJava自定义操作符

前言

RxJava不仅提供了大量的操作,例如mapflatMap相关博客),还支持自定义操作符。
官方文档给出了自定义操作符的相关建议:
如果操作符是用于Observable发射的单独的数据项,则使用序列化操作符ObservableOperator
如果你的操作符是用于变换Observable发射的整个数据序列,则使用变换操作符ObservableTransformer

自定义序列化操作符

最近项目中有了这样一个需求:从后台获取了原始数据DataA,在前端加工处理后成DataB提交给后台。项目中大量地方使用了这个方法,刚开始是使用了一个Utils进行数据转换。但是我发现项目中的网络请求都是使用RxJava实现的。那么RxJava中有没有什么优雅的实现数据转换呢?我首先想到的是map操作符,但是每次使用map还要传入转换逻辑,真的很麻烦。而序列化操作符干好可以完美的实现我们的要求。接下来我们就通过一个简单的例子来看如何自定义序列化操作符。
假设存在一个这样的User的实例,我们要从中获取到它的name

class User {
    private String name;
    private List<String> book;
}

这是个伪需求啊,我们完全可以使用map操作符实现这个功能:

map(new Function<User, String>() {
    @Override
    public String apply(User user) throws Throwable {
        return user.getName();
    }
})

但这中方法每次都要写一遍转换逻辑,也就是return user.getName()。如果转换逻辑很复杂呢,如果我们不想关心转换过程,但业务中却大量需要呢?接下来就是轮到自定义操作符出场了。
首先,我们自定义一个ObservableOperator

public class UserToName<String>
        implements ObservableOperator<String, User> {
    @Override
    public Observer apply(Observer observer) {

        return new Observer<User>() {

            private Disposable mDisposable;

            @Override
            public void onSubscribe(Disposable d) {

                mDisposable = d;
                observer.onSubscribe(d);
            }

            @Override
            public void onNext(User o) {

                if (!mDisposable.isDisposed()) {
                    observer.onNext(o.getName());
                }
            }

            @Override
            public void onError(Throwable e) {

                if (!mDisposable.isDisposed()) {
                    observer.onNext(e);
                }
            }

            @Override
            public void onComplete() {

                if (!mDisposable.isDisposed()) {
                    observer.onComplete();
                }
            }
        };
    }
}

接下来使用lift操作符搭配使用它:

  User dostoyevsky = new User("陀思妥耶夫斯基", book1);
  Observable.just(dostoyevsky)
                  .lift(new UserToName<String>())
                  .subscribe(new Consumer<String>() {

                      @Override
                      public void accept(String s) throws Throwable {

                          System.out.println(s);
                      }
                  });
>>>陀思妥耶夫斯基

业务逻辑处只要一行代码就可以实现变换操作。
UserToName这个类实现了ObservableOperator接口,你也可以重写UserToName的构造方法做一些初始化操作。
ObservableOperator的源码如下:

public interface ObservableOperator<Downstream, Upstream> {
    @NonNull
    Observer<? super Upstream> apply(@NonNull Observer<? super Downstream> observer) throws Exception;
}

这段代码很简单,他做了一个将一个方法用于原始的Observer并返回一个新的Observer。用新的Observer监听原始的Observable。而left也会返回一个新的Observable,该Observable发送String类型的数据,用原始的Observer去订阅它。其中Downstream代表转换后的数据流,Upstream代表转换前的数据流。详细的原理参考从源码查看RxJava中的map和flatMap的用法与区别

自定义变换操作符

开篇就说到序列化操作符只能对Observable发射的单独的数据项进行处理,也就是这能对那个user进行操作,但对这个Observable却无能无力,例如我们想要打印上述user中所有的书名book。和上文中的一样,第一个想到的操作肯定是使用flatMap

flatMap(new Function<User, ObservableSource<?>>() {

                      @Override
                      public ObservableSource<?> apply(User user) throws Throwable {

                          return Observable.fromIterable(user.getBook());
                      }
                  })

但是我偏不,我就要自己去实现。

image

首先实现一个ObservableTransformer

public class UserTransformer implements ObservableTransformer<User, String> {

    @Override
    public ObservableSource<String> apply(Observable<User> upstream) {

        return upstream.flatMap(new Function<User, ObservableSource<String>>() {

            @Override
            public ObservableSource<String> apply(User user) throws Throwable {

                return Observable.fromIterable(user.getBook());
            }
        });
    }
}

接下来使用compose操作符实现它:

Observable.just(dostoyevsky)
                  .compose(new UserTransformer())
                  .subscribe(new Consumer<String>() {

                      @Override
                      public void accept(String s) throws Throwable {
                          System.out.println(s);
                      }
                  });

我们看看ObservableTransformer的源码:

public interface ObservableTransformer<Upstream, Downstream> {
    @NonNull
    ObservableSource<Downstream> apply(@NonNull Observable<Upstream> upstream);
}

什么鬼玩意儿哦!这东西的上游数据类型标注位置和ObservableOperator刚好相反!!

  • ObservableOperator<Downstream, Upstream>
  • ObservableTransformer<Upstream, Downstream>
    这些我都不在乎,看看它干了什么?
    将函数应用于上游原始的Observable并返回具有可选的不同元素类型的ObservableSource。其中Downstream就是用来指定不同元素的类型。

二者的区别

看完代码相信已经基本了解了它们的区别了:

  • 前者作用于用于观察者层面,只对原始的被观察者发出的数据进行变换
  • 后者作用于整个序列,对被观察进行了变化。

总结

完了。求大神带我

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

推荐阅读更多精彩内容

  • 一、RxJava操作符概述 RxJava中的操作符就是为了提供函数式的特性,函数式最大的好处就是使得数据处理简洁易...
    无求_95dd阅读 3,006评论 0 21
  • 一、RxJava操作符概述 RxJava中的操作符就是为了提供函数式的特性,函数式最大的好处就是使得数据处理简洁易...
    测天测地测空气阅读 626评论 0 1
  • 一、RxJava操作符概述 RxJava中的操作符就是为了提供函数式的特性,函数式最大的好处就是使得数据处理简洁易...
    王帅Alex阅读 19,059评论 21 98
  • 在正文开始之前的最后,放上GitHub链接和引入依赖的gradle代码: Github: https://gith...
    苏苏说zz阅读 677评论 0 2
  • 一、Retrofit详解 ·Retrofit的官网地址为 : http://square.github.io/re...
    余生_d630阅读 1,832评论 0 5