rxjava2.+使用教程

rxjava2.+使用教程

  • 前言
  • 基本使用
  • 线程调度
    • subscribeOn
    • observeOn
  • Rxjava的灵活使用
    • 关于Observable和Observe的简化创建
      • Observable的简化创建
      • Observe的简化
  • 操作符
    • 转换操作符
      • map
      • flatmap
      • groupBy
      • scan
      • window

前言

rxjava推出已经有相当长的一段时间了。本人作为使用rxjava的菜鸟想对一些相关的使用做一些备注和总结。由于本人写作能力有限,先推荐几篇比较优秀的文件

  1. “给 Android 开发者的 RxJava 详解”
    扔物线大神的。这个教程很不错,不过这是rxjava1时期的文章。但文章的整个思路是非常不错的。对rxjava的学习很有帮助,可以一读。
  2. 这可能是最好的RxJava 2.x 教程
    这篇文章从 原理、使用、代码、等多方面对rxjava2进行了系统的讲解。

rxjava 到底是个什么东西。扔物线大神说的很好,“异步”
rxjava的目的和 Handler、AsyncTask一样都是为了实现线程间的切换。但是他比 handler、asynctask这些都要灵活。

基本使用

  1. 创建Observable(被观察者,用来发送消息)
  2. 创建Observer(创建观察者,用来接收消息)
  3. 建立订阅关系。这里很多人会觉得奇怪,应用是观察者订阅被观察者,但是代码中却是Observable.subscribe(Observer) 看起来像是被观察者订阅了观察者。这是为了保持代码的链式结构。
//第一步: 创建 Observable(被观察者)
Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                System.out.println("+++++++++++++++++++++++++++++" + 1);
                emitter.onNext(2);
                System.out.println("+++++++++++++++++++++++++++++" + 2);
                emitter.onNext(3);
                System.out.println("+++++++++++++++++++++++++++++" + 3);
                /* 这里如果有异常的话,一定是发生在 onComplete 之前,不然异常无法被捕获处理造成闪退 */
					//String a = null;
					//a.length();
					//String[] b = {"1"};
					//b[5].length();
                //如果 onError 之前没有异常发生, 那么 onError 之后的代码将继续执行,但是不会被观察者捕获
                emitter.onError(new Throwable("Throw an error !"));
                //当我们已经抛出了一个异常那么第二个异常也无法被捕获处理造成闪退
				//emitter.onError(new Throwable("Throw second error !"));
                System.out.println("+++++++++++++++++++++++++++++" + "onError");
                emitter.onComplete();
                System.out.println("+++++++++++++++++++++++++++++" + "onComplete");
                emitter.onNext(4);
                System.out.println("+++++++++++++++++++++++++++++" + 4);
            }
        })
        //第三步:建立订阅关系
        .subscribe(new Observer<Integer>() {
        //第二步:创建observer(观察者)
            @Override
            public void onSubscribe(Disposable d) {
                Log.i(TAG + "onSubscribe", d.isDisposed() + "");
            }
            @Override
            public void onNext(Integer integer) {
                Log.i(TAG + "onNext", integer + "");
                if (integer == 3) {
                    //切换操作,观察者不再接受上游事件, 此后上游Observable将不能再抛出异常,否则异常无法被捕获处理。
                    disposable.dispose();
                }
            }
            @Override
            public void onError(Throwable e) {
                Log.e(TAG + "onError", e.getMessage().toString());
            }
            @Override
            public void onComplete() {
                Log.e(TAG + "onComplete", "onComplete");
            }
        });

总结: 这里是一些注意点有点绕,初学者可以暂且跳过

  1. 如果在消息源中有意外的异常抛出,那么异常将被observer捕获并在onError处理,并且中断整条链式代码的执行。如上代码中 a.lenght() 执行后将在observer中的onError方法中捕获 NullPointException 异常,并且这之后的代码将不再执行。
  2. 消息源中 emitter.onErroremitter.onComplete()被调用后订阅关系消息源中的代码将继续执行,但观察者将不会对任何发出的消息进行处理。
    注意: 当订阅关系取消后,消息源不能再以任何形式抛出异常,即使是emitter.onError这样有意识的操作,因为此时异常抛出后将不会被捕获处理。

线程调度

先看代码:

        observable
              //指定发射事件的线程为 io 线程
              .subscribeOn(Schedulers.io())
              //指定接收者线程为 Android主线程
              .observeOn(AndroidSchedulers.mainThread())
              .subscribe(observer1);

subscribeOn

此方法用于指定消息源发生的线程

observeOn

此方法用于指定消息处理的线程
注意:

  1. 多次指定消息源的线程只有第一次有效,subscribeOn只在第一次调用的时候有效
  2. 但是消息处理的线程可以多次切换,也就是说每调用一次observeOn消息处理的线程就切换一次
  3. RxJava 中,已经内置了很多线程选项供我们选择,例如有:
  • Schdulers.io() 代表io操作的线程, 通常用于网络,读写文件等io密集型的操作;
  • Schdulers.computation() 代表CPU计算密集型的操作, 例如需要大量计算的操作;
  • Schdulers.newThread() 代表一个常规的新线程;
  • AndroidSchdulers.mainThread() 代表Android的主线程;
    rxjava 内置的这些Scheduler 足够满足我们的需求,而且内部的线程调度采用线程池,效率也较高

Rxjava的灵活使用

通过以上我们简单的了解了。rxjava的基本使用。但如果rxjava仅仅是这样的话是不能满足多样的使用场景的,那也太弱了。下面我们来看看rxjava那些灵活的使用。

关于Observable和Observe的简化创建

Observable的简化创建

create() 方法是Rxjava中创建事件序列的最基本的方法。除此之外,rxjava还提供了一下快捷创建事件序列的方法

  • just(T...)
        /*
        just(T...)方法将依次发射 1,2,3,4等事件,相当于 执行 onNext(1), onNext(2), onNext(3) onNext(4);
        just方法最大的参数个数为 10。
        */
        Observable.just(1, 2, 3, 4).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                //此处将依次收到 1,2,3,4等 4 个消息
                System.out.println("justjustjustjustjustjustjust------" + integer);
            }
        });
  • fromArray
        /*
            fromArray 方法的效果和just,fromIterable一样,只是接收的参数是一个数组。
            当然,fromArray(1, 2, 3, 4) 像这样调用也是一样的。
            显然的fromArray方法的参数个数是没有限制的。
         */
        Integer[] strings1 = {1, 2, 3, 4};
        Observable.fromArray(strings1).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                System.out.println("fromArrayfromArrayfromArrayfromArray++++++++" + integer);
            }
        });
  • fromIterable
        List<String> stringList = new ArrayList<>();
        stringList.add("1");
        stringList.add("2");
        stringList.add("3");
        stringList.add("4");
        /*
            fromIterable 将依次发射 1,2,3,4,等4个事件,效果和上面just方法类似,
            但,很明显的fromIterable方法将能承载更多的数据
         */
        Observable.fromIterable(stringList).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                System.out.println("fromfromfromfromfromfromfromfrom-------" + s);
            }
        });

Observe的简化

如上例子中,如果我们不需要对 异常、完成 等信息进行处理,那么直接订阅一个consume作为观察者即可。
当然rxjava也提供了不同参数个数的subscribe()方法,可以根据需求设置捕获 异常 或 完成 等消息

操作符

为了方便使用,以及满足各种使用场景,rxjava提供了众多的方法,rxjava官方称之为“操作符”。当然上述Observable的各种创建方法也是操作符。下面我们来看一下常用的操作符。

转换操作符

map

        Observable.just(1, 2, 3, 4)
                .map(new Function<Integer, String>() {
                    @Override
                    public String apply(Integer integer) throws Exception {
                    //将源消息中的integer 值转换成我们需要的 String值
                        return "The value is " + integer;
                    }
                }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                System.out.println("------------" + s);
            }
        });

map是一个比较简单的转换操作符,通过规则将源消息中的 值,转换成我们需要的值

flatmap

        Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9)
                .flatMap(new Function<Integer, ObservableSource<String>>() {
                    @Override
                    public ObservableSource<String> apply(Integer integer) throws Exception {
                        String a = integer + "";
                        return Observable.just(a).delay(10, TimeUnit.SECONDS);
                    }
                })
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {
                        System.out.println("+++++++++++++++" + s);
                    }
                });

如上代码,flatMap将integer类型的消息转换成了String类型的消息。这里要注意,flatMap是无序的
当然flatMap有很多其他变体,(如可以可以出来异常、完成时间的flatMap(Function onNextMapper, Function onErrorMapper, Callable))等等。这里我只讲最基本的。

groupBy

groupby将源Observable拆分成多个GroupedObservable,每个GroupedObservable发射一个Observable中的子序列。

        Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9)
                .groupBy(new Function<Integer, Integer>() {
                    @Override
                    public Integer apply(Integer integer) throws Exception {
                        //根据原始消息的不同,将源Observable拆分成不同的GroupedObservable。
                        // 并给下游消息队列(即GroupedObservable)加上不同的 key 值
                        if (integer % 2 == 0) {
                            return 2;
                        } else {
                            return 1;
                        }
                    }
                }).subscribe(new Consumer<GroupedObservable<Integer, Integer>>() {
            @Override
            public void accept(GroupedObservable<Integer, Integer> integerIntegerGroupedObservable) throws Exception {
                //获取消息队列的 key之,采用 key 值来分辨消息队列的种类
                int key = integerIntegerGroupedObservable.getKey();
                switch (key) {
                    case 1:
                        integerIntegerGroupedObservable
                                .subscribe(new Consumer<Integer>() {
                            @Override
                            public void accept(Integer integer) throws Exception {
                                System.out.println("---------------" + integer + " is a 奇数" );
                            }
                        });
                        break;
                    case 2:
                        integerIntegerGroupedObservable.subscribe(new Consumer<Integer>() {
                            @Override
                            public void accept(Integer integer) throws Exception {
                                System.out.println("+++++++++++++++" + integer + " is a 偶数" );
                            }
                        });
                        break;
                    default:
                        break;
                }
            }
        });

这里有一个 groupby 的变种,groupBy(Function keySelector, Function valueSelector) 其中第二个参数是对消息的值进行的变换。

scan

        Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9)
                .scan(new BiFunction<Integer, Integer, Integer>() {
                    @Override
                    public Integer apply(Integer sum, Integer item) throws Exception {
                        //return值 将作为下次调用此函数的第一个参数值
                        //注意:这里会先将第一个消息发出给订阅者来处理。
                        // 然后再将第一个消息的值作为此函数的第一个参数,将第二个消息作为第二个参数来第一次执行这个函数
                        return sum + item;
                    }
                }).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                System.out.println("===========" + integer);
            }
        });

从代码运行结果看出,scan使得订阅者每次接收到的消息值都和上一次的消息值有关。*注意:*第一次的消息是不变的并会作为apply方法第一次执行的第一个参数。当然我们也可以改变scan返回的消息的数据类型,这时候就要调用scan(final R initialValue, BiFunction accumulator)来设置观察者接收到的第一个消息的初始值 initialValue;

window

window 操作符合buffer操作符类似。但buffer是将消息源转换成一个个列表发射,而window是将消息源转换成多个Observable,每个Observable发射一个子集。

        Observable.fromArray(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)
                .window(3)
                .subscribe(new Consumer<Observable<Integer>>() {
                    @Override
                    public void accept(Observable<Integer> integerObservable) throws Exception {
                        System.out.println("==================" + "第" + time + "组");
                        time ++;
                        integerObservable.subscribe(new Consumer<Integer>() {
                            @Override
                            public void accept(Integer integer) throws Exception {
                                System.out.println("----------" + integer);
                            }
                        });
                    }
                });

你可能感兴趣的:(Android)