RxJava初探

众所周知,rxjava是一种响应式编程,也可以叫做观察者模式,简单来形容一下就是:
观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。在观察者模式中,主题是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅并接收通知
直接上代码:(本篇的代码中部分使用了lambda,看的时候如果费解,望谅解)

 /**
  *   被观察者
   * 1.0泛型为被操作的类型
   * 1.1emitter称为发射器
   * 1.2有三种发射的方法,分别是
   * void onNext(T value)、void onError(Throwable error)、onComplete(),
   * onNext方法可以无限调用,Observer(观察者)所有的都能接收到,
   * onError和onComplete是互斥的,Observer(观察者)只能接收到一个,
   * OnComplete可以重复调用,但是Observer(观察者)只会接收一次,
   * 而onError不可以重复调用,第二次调用就会报异常。
   */
    static Observable mObservable = Observable.create((ObservableOnSubscribe<String>) emitter -> {
        emitter.onNext("连载1");
        emitter.onNext("连载2");
        emitter.onNext("连载3");
        emitter.onComplete();
    });
    被观察者通过发射器emitter发射 onNext、onError、onComplete三种事件,读者通过订阅不同的事件作出不同的响应
    /**
     * 观察者
     */
    static Observer<String> reader = new Observer<String>() {
        @Override
        public void onSubscribe(Disposable d) {
            //处理观察者和被观察者的,如果观察者不想再订阅了,请调用
            //d.dispose();
            System.out.println("onSubscribe---" + d.isDisposed());
            //CompositeDisposable类
            //1、可以快速解除所有添加的Disposable类.
            //2、每当我们得到一个Disposable时就调用CompositeDisposable.add()将它添加到容器中,
            //在退出的时候, 调用CompositeDisposable.clear() 即可快速解除.
        }

        //跟emitterd对应
        @Override
        public void onNext(String s) {
            System.out.println("onNext---" + s);
        }

        //跟emitterd对应
        @Override
        public void onError(Throwable e) {
            System.out.println("onError---" + e.getMessage());
        }

        //跟emitterd对应
        @Override
        public void onComplete() {
            System.out.println("onComplete---");
        }
    };
    最后,我们在两者之间建立订阅关系
      /**
       *  观察者被观察者建立订阅关系
       * 只有观察者和被观察者建立了订阅关系才会如此
       */
   mObservable.subscribe(reader);
   //此处插播一句  被观察者可以有一个空订阅
   //mObservable.subscribe();

我们使用rxjava非常重要的一个原因就是它能非常方便的进行线程切换,不像上边那样的建立被观察者,观察者然后建立订阅关系,本次示例,我们使用链式调用来展示rxjava的线程切换

/**2.0
 *rxjava调度器Scheduler以及rxjava的链式调用
  * 2.1多次指定上游的线程(执行的线程subscribeOn)只有第一次指定的有效,
  * 也就是说多次调用subscribeOn() 只有第一次的有效, 其余的会被忽略.
  * 2.2多次指定下游的线程是可以的,
  * 也就是说每调用一次observeOn() , 下游的线程就会切换一次.
  * 关于线程
  * 在RxJava中, 已经内置了很多线程选项供我们选择, 例如有:
  * Schedulers.io()                 代表io操作的线程, 通常用于网络,读写文件等io密集型的操作
  * Schedulers.computation()        代表CPU计算密集型的操作, 例如需要大量计算的操作
  * Schedulers.newThread()          代表一个常规的新线程
  * AndroidSchedulers.mainThread()  代表Android的主线程
  */
     Observable.create((ObservableOnSubscribe<String>) emitter -> {
         emitter.onNext("-----连载1");
         emitter.onNext("-----连载2");
         emitter.onNext("-----连载3");
         emitter.onComplete();
     }).observeOn(AndroidSchedulers.mainThread())//回调在主线程
       .subscribeOn(Schedulers.io())//执行在io线程
       .subscribe(new Observer<String>() {
           @Override
           public void onSubscribe(Disposable d) {
               //处理观察者和被观察者的,如果观察者不想再订阅了,请调用
               //d.dispose();
               System.out.println("-----onSubscribe---"+d.isDisposed());
           }
           //跟emitterd对应
           @Override
           public void onNext(String s) {
               System.out.println("-----onNext---"+s);
           }
           //跟emitterd对应
           @Override
           public void onError(Throwable e) {
               System.out.println("-----onError---"+e.getMessage());
           }
           //跟emitterd对应
           @Override
           public void onComplete() {
               System.out.println("------onComplete---");
           }
     });

观察者可以只订阅onnext方法

 mObservable.subscribe(new Consumer() {
            @Override
            public void accept(Object o) throws Exception {
                System.out.println("accept---" + o);
            }
        });

rxjava另一个神奇的操作地方在于操作符,比如
map、flatMap、concatMap

        /**rvjava操作符
         * 5.1map变换操作符
         */
        Observable.create((ObservableOnSubscribe<Integer>) emitter -> {
            emitter.onNext(1);
            emitter.onNext(2);
            emitter.onNext(3);
        }).map(integer -> "This is result " + integer).subscribe(s -> {
            System.out.println("accept---" + s);
        });
        /**
         *@describe 5.2flatMap操作符
         * FlatMap将一个发送事件的上游Observable变换为多个发送事件的Observables,
         * 然后将它们发射的事件合并后放进一个单独的Observable里
         * 不保证顺序
         */
        Observable.create((ObservableOnSubscribe<Integer>) emitter -> {
            emitter.onNext(1);
            emitter.onNext(2);
            emitter.onNext(3);
        }).flatMap((Function<Integer, ObservableSource<String>>) integer -> {
            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(s -> {
            System.out.println("accept---" + s);
        });
        /**
         *@describe 5.3concatMap操作符
         * concatMap将一个发送事件的上游Observable变换为多个发送事件的Observables,
         * 然后将它们发射的事件合并后放进一个单独的Observable里
         * flatMap操作符的作用就是把一个Observable转换为另一个Observable
         * 比如先登录后注册
         * 保证顺序
         */
        Observable.create((ObservableOnSubscribe<Integer>) emitter -> {
            emitter.onNext(1);
            emitter.onNext(2);
            emitter.onNext(3);
        }).concatMap((Function<Integer, ObservableSource<String>>) integer -> {
            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(s -> {
            System.out.println("accept---" + s);
        });
        /**
         *@describe 5.4concatMap操作符
         * concatMap将一个发送事件的上游Observable变换为多个发送事件的Observables,
         * 然后将它们发射的事件合并后放进一个单独的Observable里
         * 保证顺序
         * 接收和失败
         */
        Observable.create((ObservableOnSubscribe<Integer>) emitter -> {
            emitter.onNext(1);
            emitter.onNext(2);
            emitter.onNext(3);
        }).concatMap((Function<Integer, ObservableSource<String>>) integer -> {
            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(s -> {
            System.out.println("accept---" + s);
        }, throwable -> {
            System.out.println("throwable---" + throwable.getMessage());
        });

/**
         *@describe 5.5zip操作符
         * Zip通过一个函数将多个Observable发送的事件结合到一起,
         * 然后发送这些组合到一起的事件. 它按照严格的顺序应用这个函数。
         * 它只发射与发射数据项最少的那个Observable一样多的数据
         * 比如页面数据需要几个接口返回数据
         * 可以通过zip来打包请求 ,返回所有数据
         */
        Observable observable1 = Observable.create((ObservableOnSubscribe<Integer>) emitter -> {
            emitter.onNext(1);
            emitter.onNext(2);
            emitter.onNext(3);
            emitter.onNext(4);
            emitter.onComplete();
        }).subscribeOn(Schedulers.io());
        Observable observable2 = Observable.create((ObservableOnSubscribe<String>) emitter -> {
            emitter.onNext("A");
            emitter.onNext("B");
            emitter.onNext("C");
            emitter.onComplete();
        }).subscribeOn(Schedulers.io());
        Observable.zip(observable1, observable2, (BiFunction<Integer, String, String>) (integer, s) -> integer+s)
        .subscribeOn(AndroidSchedulers.mainThread())
        .subscribe(o -> {
            System.out.println("accept---" + o);
        }, throwable -> {

        });

在这里插入图片描述在这里插入图片描述组合的过程是分别从 两根水管里各取出一个事件 来进行组合, 并且一个事件只能被使用一次, 组合的顺序是严格按照事件发送的顺利 来进行的, 也就是说不会出现圆形1 事件和三角形B 事件进行合并, 也不可能出现圆形2 和三角形A 进行合并的情况.
最终下游收到的事件数量 是和上游中发送事件最少的那一根水管的事件数量 相同
组合操作符:merge,zip,join
merge、 Join
Join操作符
join(Observable, Func1, Func1, Func2)我们先介绍下join操作符的4个参数:

Observable:源Observable需要组合的Observable,这里我们姑且称之为目标Observable;

Func1:接收从源Observable发射来的数据,并返回一个Observable,
这个Observable的声明周期决定了源Obsrvable发射出来的数据的有效期;

Func1:接收目标Observable发射来的数据,并返回一个Observable,
这个Observable的声明周期决定了目标Obsrvable发射出来的数据的有效期;

Func2:接收从源Observable和目标Observable发射出来的数据,并将这两个数据组合后返回。

所以Join操作符的语法结构大致是这样的:onservableA.join(observableB, 控制observableA发射数据有效期的函数, 控制observableB发射数据有效期的函数,两个observable发射数据的合并规则)

join操作符的效果类似于排列组合,把第一个数据源A作为基座窗口,他根据自己的节奏不断发射数据元素,第二个数据源B,每发射一个数据,我们都把它和第一个数据源A中已经发射的数据进行一对一匹配;举例来说,如果某一时刻B发射了一个数据“B”,此时A已经发射了0,1,2,3共四个数据,那么我们的合并操作就会把“B”依次与0,1,2,3配对,得到四组数据: [0, B] [1, B] [2, B] [3, B]
描述示例:

final List<House> houses = DataSimulator.getHouses();//模拟的房源数据,用于测试

//用来每秒从houses总取出一套房源并发射出去
Observable<House> houseSequence =
        Observable.interval(1, TimeUnit.SECONDS)
                .map(new Func1<Long, House>() {
                    @Override
                    public House call(Long position) {
                        return houses.get(position.intValue());
                    }
                }).take(houses.size());//这里的take是为了防止houses.get(position.intValue())数组越界

//用来实现每秒发送一个新的Long型数据
Observable<Long> tictoc = Observable.interval(1, TimeUnit.SECONDS);

houseSequence.join(tictoc,
        new Func1<House, Observable<Long>>() {
            @Override
            public Observable<Long> call(House house) {
            	//控制houseSequence延迟两秒发射一次数据 
                return Observable.timer(2, TimeUnit.SECONDS);
            }
        },
        new Func1<Long, Observable<Long>>() {
            @Override
            public Observable<Long> call(Long aLong) {
            	//控制tictoc不延迟发送数据
                return Observable.timer(0, TimeUnit.SECONDS);
            }
        },
        new Func2<House, Long, String>() {
            @Override
            public String call(House house, Long aLong) {
                //数据合并
                return aLong + "-->" + house.getDesc();
            }
        }
).subscribe(new Observer<String>() {
    @Override
    public void onCompleted() {
        System.exit(0);
    }

    @Override
    public void onError(Throwable e) {
        System.out.println("Error:"+e.getMessage());
    }

    @Override
    public void onNext(String s) {
        System.out.println(s);
    }
});
打印结果:
0-->中粮海景壹号新出大平层!总价4500W起
1-->中粮海景壹号新出大平层!总价4500W起
1-->满五唯一,黄金地段
2-->中粮海景壹号新出大平层!总价4500W起
2-->满五唯一,黄金地段
2-->一楼自带小花园
3-->一楼自带小花园
3-->毗邻汤臣一品
4-->毗邻汤臣一品
4-->顶级住宅,给您总统般尊贵体验
5-->顶级住宅,给您总统般尊贵体验
5-->顶层户型,两室一厅
6-->顶层户型,两室一厅
6-->南北通透,豪华五房
7-->南北通透,豪华五房

compose操作符
场景一:
我们可以用 compose 操作符来进行线程的切换,一般用在网络请求的地方。
原始的写法为:

.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

封窗成工具类

Java版本:
public class RxThreadUtils {

    /**
     * Flowable 切换到主线程
     */
    public static <T> FlowableTransformer<T, T> flowableToMain() {
        return upstream -> upstream.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

    /**
     * Observable 切换到主线程
     */
    public static <T> ObservableTransformer<T, T> observableToMain() {
        return upstream -> upstream.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

    /**
     * Maybe 切换到主线程
     */
    public static <T> MaybeTransformer<T, T> maybeToMain() {
        return upstream -> upstream.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }
}
Kotlin版本:
object RxThreadUtils {

    /**
     * Observable 切换到主线程
     */
    fun <T> observableToMain(): ObservableTransformer<T, T> {
        return ObservableTransformer { upstream ->
            upstream.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
        }
    }

    /**
     * Flowable 切换到主线程
     */
    fun <T> flowableToMain(): FlowableTransformer<T, T> {
        return FlowableTransformer { upstream ->
            upstream.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
        }
    }

    /**
     * Maybe 切换到主线程
     */
    fun <T> maybeToMain(): MaybeTransformer<T, T> {
        return MaybeTransformer { upstream ->
            upstream.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
        }
    }
}

优化调用:

.compose(RxThreadUtils.flowableToMain())

使用场景二
compose 操作符可以和 Transformer 结合使用,一方面可以让代码看起来更加简洁,另一方面能够提高代码的复用性,因为 RxJava 提倡链式调用,我们可以合理的使用 compose 操作符来防止链式调用被打破。

RxLifecycle 是 trello 开源的一个配置 RxJava 使用的开源库,我们知道 RxJava 有个缺点就是会导致内存泄露,此时,RxLifecycle 横空出世了,它可以配合 RxJava 一起使用,可以有效防止内存泄漏发生,使用起来也是非常方便,举个简单的例子:

myObservable
    .compose(RxLifecycle.bind(lifecycle))
    .subscribe();

Github
知乎开源
///背压相关///
如果把rxjava比作水管,相信很多东西也是很好理解的,如果没有切换线程 ,
水管的上游跟下游会是一根水管,上游发送多少事件,下游就处理多少事件,
不会产生阻塞,但是如果切换了线程,因为上下游不再一根水管里,如果下游的的水管不知道处理什么原因流的慢了(比如处理一些耗时操作)上游发送的数据因为来不及处理就是越积越多,最终内存爆掉了,那么上游发送的数据都存到什么地方去了呢,可以理解为有一个瓮来保存这些数据,但是因为这个我瓮是个固定大小,所以当达到他的存储上限之后,这个瓮就爆炸了,
根据这个思路,我们防止这个瓮被爆掉有如下几种方式:
一是从数量上进行治理, 减少发送进水缸里的事件
二是从速度上进行治理, 减缓事件发送进水缸的速度

//1.通过filter操作符过滤发送事件,达到控量的目的
Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                for (int i = 0; ; i++) {
                    emitter.onNext(i);
                }
            }
        }).subscribeOn(Schedulers.io())
                .filter(new Predicate<Integer>() {
                    @Override
                    public boolean test(Integer integer) throws Exception {
                        return integer % 10 == 0;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.d(TAG, "" + integer);
                    }
                });


//2.0sample操作符, 这个操作符每隔指定的时间就从上游中取出一个事件发送给下游
//虽然上游仍然一直在不停的发事件, 但是我们只是每隔一定时间取一个放进瓮里, 并没有全部放进瓮里
Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                for (int i = 0; ; i++) {
                    emitter.onNext(i);
                }
            }
        }).subscribeOn(Schedulers.io())
                .sample(2, TimeUnit.SECONDS)  //sample取样
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.d(TAG, "" + integer);
                    }
                });
这两种方式最大的缺点就是会丢失大部分事件,如果我们既不想丢失事件又不想让内存爆掉的话,我们可以控制上游发送事件的速度
比方说对上游发送事件做一个延时处理

还有一种方式用来解决内存溢出的问题,就是背压
所谓背压就是:
上游变成了Flowable, 下游变成了Subscriber, 但是水管之间的连接还是通过subscribe()
他有四种处理策略:
BackpressureStrategy.BUFFER 大水缸
BackpressureStrategy.ERROR 128的水缸
BackpressureStrategy.DROP 直接把消费不了的事件丢弃
BackpressureStrategy.LATEST 就是只保留最新的事件

	  //链式调用
      Flowable.create((FlowableOnSubscribe<Integer>) emitter -> {
          emitter.onNext(1);
          emitter.onNext(2);
          emitter.onNext(3);
          emitter.onComplete();
          //这种方式会在出现上下游流速不均衡的时候直接抛出一个异常,
          //这个异常就是著名的MissingBackpressureException
      },BackpressureStrategy.ERROR).subscribeOn(Schedulers.io())
              .observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<Integer>() {
          @Override
          public void onSubscribe(Subscription s) {
              //一定要设置 request当做是一种能力, 当成Subscriber处理事件的能力
              //在Flowable里默认有一个大小为128的水缸, 当上下游工作在不同的线程中时,
              //上游就会先把事件发送到这个水缸中, 因此, 下游虽然没有调用request,
              //但是上游在水缸中保存着这些事件, 只有当下游调用request时, 才从水缸里取出事件发给下游.
              s.request(Long.MAX_VALUE);
          }
          @Override
          public void onNext(Integer integer) {
              System.out.println("onNext---" + integer);
          }
          @Override
          public void onError(Throwable t) {
              System.out.println("onError---" + t.getMessage());
          }
          @Override
          public void onComplete() {
              System.out.println("onComplete---");
          }
      });
      ----------------------------分割线---------------------------------
      Flowable.interval(1, TimeUnit.MICROSECONDS)
              .onBackpressureDrop()  //加上背压策略
              .observeOn(AndroidSchedulers.mainThread())
              .subscribe(new Subscriber<Long>() {
                  @Override
                  public void onSubscribe(Subscription s) {
                      s.request(128);
                      s.request(Long.MAX_VALUE);
                  }

                  @Override
                  public void onNext(Long aLong) {
                      try {
                          Thread.sleep(1000);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  }

                  @Override
                  public void onError(Throwable t) {
                  }

                  @Override
                  public void onComplete() {

                  }
              });

和Observable功能几乎一模一样,★★背压策略,一定要在线程变换之前去调用★★
//区别在于:
//1.定义的类功能不一样
//2.Flowable可以通过Subscription对象,调用request(n),响应式拉取数据,来支持背压特性 //io.reactivex.Flowable
//3.★★背压策略,一定要在线程变换之前去调用★★
除了这两种还有以下几种:
//基本都使用他
//io.reactivex.Observable
//这个流只会收到一个数据或者一个error,也就是要不然执行onSuccess要不然就执行onError
//io.reactivex.single
//和Single类似正常流程也是只执行onSuccess,但在出现错误的时候,可以选择是执行onError还是onComplete
//io.reactivex.Maybe
//这个流没有数据,只会收到error或者complete
//io.reactivex.Completable
参考链接:
https://www.jianshu.com/p/1922bd75ee73
相关博客
https://www.jianshu.com/p/cd3557b1a474
该系列有十篇
https://www.jianshu.com/p/464fa025229e
↓↓↓↓
https://www.jianshu.com/u/c50b715ccaeb

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值