Android 函数响应式编程(RxJava3)

操作符字典

参考地址

一、RxJava 基本用法

说到异步操作,我们会想到 Android 的 AsyncTask 和 Handler。但是随着请求的数量越来越多,代码逻辑将会变得越来越复杂,而 RxJava 却能保持清晰的逻辑。RxJava 的原理就是创建一个 Observable(被观察者) 对象来干活,然后使用各种操作符建立起来的链式操作,就如同流水线一样,把想要处理的数据一步步加工成成品,再发射给 Observer(观察者) 处理。

RxJava 的异步操作是通过扩展的观察者模式实现的。

1.1、配置 gradle

github-RxJava
github-RxAndroid

    implementation 'io.reactivex.rxjava3:rxjava:3.0.0'
    implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

其中 RxAndroid 是 RxJava 在 Android 平台的扩展。它包含了一些能够简化 Android 开发的工具,比如特殊的调度器。

1.2、RxJava3 基本实现

RxJava2 和 RxJava1

参考博客1

参考博客2

1.2.1、创建 Observer(观察者)

         Observer<String> observer = new Observer<String>() {
            private Disposable disposable;

            @Override
            public void onSubscribe(@NonNull Disposable d) {
                Log.d("TAG", "onSubscribe");
                disposable = d;
            }

            @Override
            public void onNext(@NonNull String s) {
                Log.d("TAG", "onNext:" + s);
                if (s.equals("王五")) {
                    disposable.dispose();
                }
            }

            @Override
            public void onError(@NonNull Throwable e) {
                Log.d("TAG", "onError");
            }

            @Override
            public void onComplete() {
                Log.d("TAG", "onComplete");
            }
        };
  • onSubscribe: 事件订阅成功回调。
    在事件发送之前调用,可以用于一些准备工作,例如数据的清零或重置。返回了一个 Disposable 实例,当调用 disposable.dispose() 时,观察者就不再处理后面的事件。
  • onNext:发送数据时被多次调用。
    普通的事件。将要处理的事件添加到事件队列中。
  • onError:出错时被调用。
    事件队列异常。在事件处理过程中出现异常时,onError 会被触发,同时队列自动终止,不允许再有事件发出。
  • onComplete:完成时被调用。
    事件队列完结。RxJava 不仅把每个事件单独处理,其还会把它们看作一个队列。当不会再有新的 onNext 发出时,需要触发 onComplete 方法作为完成标志。

1.2.2、 创建 Observable(被观察者)

通过调用 onNext 方法,不断地将事件添加到任务队列中。onError 和 onComplete 在事件的最后出现,并且它们是互斥的。

        Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> emitter) throws Throwable {
                emitter.onNext("张三");
                emitter.onNext("李四");
                emitter.onNext("王五");
                emitter.onNext("赵六");
                emitter.onNext("孙七");
                // 调用出错方法
                //emitter.onError(new IllegalArgumentException("Test Exception!"));
                // 调用完成方法
                emitter.onComplete();
            }
        });

也可以用 just 方法。

        Observable<String> observable1 = Observable.just("张三", "李四", "王五");

还可以用 fromArray 方法。

        String[] names = {"张三", "李四", "王五"};
        Observable<String> observable2 = Observable.fromArray(names);

1.2.3、Subscribe(订阅)

        observable.subscribe(observer);

另外:观察者 Obaserver 的 subscribe 具有多个重载的方法。

    //观察者不对被观察者发送的事件做出响应(但是被观察者还可以继续发送事件)
    public final Disposable subscribe()
 
    //观察者对被观察者发送的任何事件都做出响应
    public final void subscribe(Observer<? super T> observer)
 
    //表示观察者只对被观察者发送的Next事件做出响应
    public final Disposable subscribe(Consumer<? super T> onNext)
 
    //表示观察者只对被观察者发送的Next & Error事件做出响应
    public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError)
 
    //表示观察者只对被观察者发送的Next & Error & Complete事件做出响应
    public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError,
                                      Action onComplete)
 
    //表示观察者只对被观察者发送的Next & Error & Complete & onSubscribe事件做出响应
    public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError,
                                      Action onComplete, Consumer<? super Disposable> onSubscribe)

1.3、RxJava3 基本实现(背压)

参考博客

上面的例子中,如果 在 Observable(被观察者)中张三、李四、王五、赵六、孙七是每隔 1 秒发送一个,而在 Observer(观察者)中却要 5 秒才能处理一个,如果 Observable 无限发送,由于 Observer 处理速度始终比发送的速度慢,那么事件队列就会越积越多,最终就会导致 Out Of Memory(内存溢出),这时候就需要背压上场了。

背压,就是指在异步场景中,被观察者发送事件速度远快于观察者的处理速度的情况下,一种告诉上游的被观察者降低发送速度的策略,简而言之,背压是流速控制的一种策略。

1.3.1、创建 Subscriber(观察者)

        Subscriber<String> subscriber = new Subscriber<String>() {
            private Subscription subscription;

            @Override
            public void onSubscribe(Subscription s) {
                Log.d("TAG", "onSubscribe");
                s.request(Long.MAX_VALUE);
                subscription = s;
            }

            @Override
            public void onNext(String s) {
                Log.d("TAG", "onNext:" + s);
                if (s.equals("王五")) {
                    subscription.cancel();
                }
            }

            @Override
            public void onError(Throwable t) {
                Log.d("TAG", "onError" + t);
            }

            @Override
            public void onComplete() {
                Log.d("TAG", "onComplete");
            }
        };
  • s.request 代表下游处理事件的能力。
  • onSubscribe:和 Observer 返回的是 Disposable 不同,Subscriber 返回的是 Subscription,但是通过调用 subscription.cancel(),同样可以让观察者不再处理后面的事件。

1.3.2、创建 Flowable(被观察者)

参考博客

        Flowable<String> flowable = Flowable.create(new FlowableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull FlowableEmitter<String> emitter) throws Throwable {
                emitter.onNext("张三");
                emitter.onNext("李四");
                emitter.onNext("王五");
                emitter.onNext("赵六");
                emitter.onNext("孙七");
                // 调用出错方法
                //emitter.onError(new IllegalArgumentException("Test Exception!"));
                // 调用完成方法
                emitter.onComplete();
            }
        }, BackpressureStrategy.ERROR);

背压策略:

  • BackpressureStrategy.ERROR:上游发送事件超过下游处理能力时就通过 onError 抛出 MissingBackpressureException 异常。
  • BackpressureStrategy.BUFFER:
  • BackpressureStrategy.MISSING:
  • BackpressureStrategy.DROP:
  • BackpressureStrategy.LATEST:

1.3.3、订阅

        flowable.subscribe(subscriber);

另外:观察者 Flowable 的 subscribe 也具有多个重载的方法。

    //观察者不对被观察者发送的事件做出响应(但是被观察者还可以继续发送事件)
    public final Disposable subscribe()
    
    //观察者对被观察者发送的任何事件都做出响应
    public final void subscribe(@NonNull Subscriber<@NonNull ? super T> subscriber)
    
    //表示观察者只对被观察者发送的Next事件做出响应
    public final Disposable subscribe(@NonNull Consumer<? super T> onNext)
    
    public final void subscribe(@NonNull FlowableSubscriber<@NonNull ? super T> subscriber)
    
    //表示观察者只对被观察者发送的Next & Error事件做出响应
    public final Disposable subscribe(@NonNull Consumer<? super T> onNext, @NonNull Consumer<? super Throwable> onError)
    
    //表示观察者对被观察者发送的Next & Error & Complete事件做出响应
    public final Disposable subscribe(@NonNull Consumer<? super T> onNext, @NonNull Consumer<? super Throwable> onError,
            @NonNull Action onComplete)

二、RxJava 的 Subject

Subject 既可以是一个 Observer 也可以是一个 Observable,它是连接 Observer 和 Observable 的桥梁。RxJava 提供了以下 4 种 Subject。

2.1、AsyncSubject

参考博客1

参考博客2

只会发送最后一个数据,这里只会打印 “孙七”。需要调用 onComplete,不然不会发送数据。如果原始的 Observable 因为发生了错误而终止,将不会发送数据,但是会向 Observer 传递一个异常通知。

        AsyncSubject<String> asyncSubject = AsyncSubject.create();
        asyncSubject.onNext("张三");
        asyncSubject.onNext("李四");
        asyncSubject.onNext("王五");
        asyncSubject.subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Throwable {
                Log.d("TAG", s);
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Throwable {
                Log.d("TAG", "onError");
            }
        }, new Action() {
            @Override
            public void run() throws Throwable {
                Log.d("TAG", "onComplete");
            }
        });
        asyncSubject.onNext("赵六");
        asyncSubject.onNext("孙七");
        asyncSubject.onComplete();

在这里插入图片描述

2.2、BehaviorSubject

Observer 会接收到 BehaviorSubject 被订阅之前的最后一个数据,再接收订阅之后发射过来的数据。如果 BehaviorSubject 被订阅之前没有发送任何数据,则会发送一个默认数据。

        BehaviorSubject<String> behaviorSubject = BehaviorSubject.createDefault("张三");
        behaviorSubject.onNext("赵六");
        behaviorSubject.onNext("孙七");
        behaviorSubject.subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Throwable {
                Log.d("TAG", s);
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Throwable {
                Log.d("TAG", "onError");
            }
        }, new Action() {
            @Override
            public void run() throws Throwable {
                Log.d("TAG", "onComplete");
            }
        });
        behaviorSubject.onNext("李四");
        behaviorSubject.onNext("王五");
        behaviorSubject.onComplete();

在这里插入图片描述

2.3、ReplaySubject

ReplaySubject 会发射所有来自原始 Observable 的数据给观察者,无论它们是何时订阅的。但是创建时有不同的方法,用来限制缓存数据的数量或者缓存数据的时间等,例如 createWithSize 和 createWithTime。注意不要在多个线程中调用 onNext、onComplete 和 onError 方法。这可能会导致顺序错乱,并且违反了 Observer 规则。

        ReplaySubject<String> subject = ReplaySubject.create();
        subject.onNext("张三");
        subject.onNext("李四");
        subject.subscribe(new Consumer<String>() {
            @Override
            public void accept(@NonNull String s) throws Exception {
                System.out.println(s);
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(@NonNull Throwable throwable) throws Exception {
                Log.d("TAG", "onError");
            }
        }, new Action() {
            @Override
            public void run() throws Exception {
                Log.d("TAG", "onComplete");
            }
        });
        subject.onNext("王五");
        subject.onNext("赵六");
        subject.onNext("孙七");
        subject.onComplete();

在这里插入图片描述

2.4、PublishSubject

Observer 只接收 PublishSubject 被订阅之后发送的数据。

        PublishSubject<String> subject = PublishSubject.create();
        subject.onNext("张三");
        subject.onNext("李四");
        subject.subscribe(new Consumer<String>() {
            @Override
            public void accept(@NonNull String s) throws Exception {
                System.out.println(s);
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(@NonNull Throwable throwable) throws Exception {
                Log.d("TAG", "onError");
            }
        }, new Action() {
            @Override
            public void run() throws Exception {
                Log.d("TAG", "onComplete");
            }
        });
        subject.onNext("王五");
        subject.onNext("赵六");
        subject.onNext("孙七");
        subject.onComplete();

在这里插入图片描述

三、RxJava 操作符

RxJava 操作符的类型分为创建操作符、变换操作符、过滤操作符、组合操作符、错误处理操作符、辅助操作符、条件和布尔操作符、算术和聚合操作符等。在这些操作符类型下又有很多操作符,每个操作符可能还有很多变体。下面只介绍相对常用的操作符。

3.1、创建操作符

创建操作符 create、just 和 from 在前面已经使用过。还有 defer、range、interval、start、repeat 和 timer 等。

3.1.1、interval

创建一个按固定时间间隔发射整数序列的 Observable<Long>,相当于定时器。从 0 开始,例如每隔 3s 打印一次 Log。

        Observable.interval(3, TimeUnit.SECONDS)
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Throwable {
                        Log.d("TAG", "interval:" + aLong.intValue());
                    }
                });

另外,interval 的重载方法。

    public static Observable<Long> interval(long initialDelay, long period, @NonNull TimeUnit unit)
    
    public static Observable<Long> interval(long initialDelay, long period, @NonNull TimeUnit unit, @NonNull Scheduler scheduler)
    
    public static Observable<Long> interval(long period, @NonNull TimeUnit unit, @NonNull Scheduler scheduler)
    
    public static Observable<Long> intervalRange(long start, long count, long initialDelay, long period, @NonNull TimeUnit unit)
    
    public static Observable<Long> intervalRange(long start, long count, long initialDelay, long period, @NonNull TimeUnit unit, @NonNull Scheduler scheduler)

3.1.2、range

创建发射指定范围内的整数序列的 Observable<Integer>,可以拿来替代 for 循环,发射一个范围内的有序整数序列。第一个参数是起始值,并且不小于 0;第二个参数为整数序列的个数。

        Observable.range(0, 5)
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Throwable {
                        Log.d("TAG", "range:" + integer.intValue());
                    }
                });

在这里插入图片描述
3.1.3、repeat

创建一个 N 此重复发送特定数据的 Observable。

        Observable.range(0, 3)
                .repeat(2)
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Throwable {
                        Log.d("TAG", "range:" + integer.intValue());
                    }
                });

在这里插入图片描述
另外还有其他方法。参考博客

    //不设置参数会无限重复
    public final Observable<T> repeat()
    
    //一直执行,直到条件符合就终止
    public final Observable<T> repeatUntil(@NonNull BooleanSupplier stop)
    
    //设置下次执行的时间,这种方式只能执行两次。
    public final Observable<T> repeatWhen(@NonNull Function<? super Observable<Object>, ? extends ObservableSource<?>> handler)

3.2、变换操作符

变换操作符的作用是对 Observable 发射的数据按照一定规则做一些变换操作,然后将变换后的数据发射出去。变换操作符有 map、flatMap、concatMap、switchMap、flatMapIterable、buffer、groupBy、cast、window、scan 等。

3.2.1、map

参考博客

map 操作符通过一个 Function 对象,将 Observable<T> 转换为一个新的 Observable<R> 并发射,观察者将收到新的 Observable 处理。
假设访问网络,Host 地址是经常变化的,有时是测试服务器地址,有时是正式服务器地址,但是具体页面的 URL 地址是固定的,这时候就可以用 map 操作符来进行转换。同时还将传入的 Integer 转换成了 String。

        final String host = "http://www.baidu.com/";
        Observable.just(222)
                .map(new Function<Integer, String>() {
                    @Override
                    public String apply(Integer integer) throws Throwable {
                        return host + integer;
                    }
                })
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Throwable {
                        Log.d("TAG", s);
                    }
                });

在这里插入图片描述
3.2.2、flatMap、cast

参考博客1

参考博客2

flatMap 操作符将 Observable 发送的每一个事件都变换为一个新的 Observable,然后将这些新的 Observable 要发送的事件放进一个单独的 Observable 中。flatMap 的合并允许交叉,也就是可能会交错地发送事件,不保证事件的发送顺序。通过加了 5 秒延迟可以看出并不是按照原始的顺序发送的。

cast 操作符的作用是强制将 Observable 发射的所有数据转换为指定类型。

        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
            }
        }).flatMap(new Function<Integer, ObservableSource<String>>() {
            @Override
            public ObservableSource<String> apply(Integer integer) throws Throwable {
                return Observable.create(new ObservableOnSubscribe<String>() {
                    @Override
                    public void subscribe(@NonNull ObservableEmitter<String> emitter) throws Throwable {
                        emitter.onNext(integer + "-1");
                        emitter.onNext(integer + "-2");
                        emitter.onNext(integer + "-3");
                    }
                }).delay(5, TimeUnit.SECONDS);
            }
        }).cast(String.class).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Throwable {
                Log.d("TAG", s);
            }
        });

在这里插入图片描述

再看一个例子,一个学生可以有多个课程,现在要打印所有学生的所有课程。首先是实体类。

public class Course {
    private String name;

    public Course(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
public class Student {
    private String name;
    private List<Course> courseList = new ArrayList<>();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Course> getCourseList() {
        return courseList;
    }

    public void setCourseList(List<Course> courseList) {
        this.courseList = courseList;
    }
}

初始化数据。

        List<Course> courses1 = new ArrayList<>();
        List<Course> courses2 = new ArrayList<>();
        Student student1 = new Student();
        Student student2 = new Student();
        courses1.add(new Course("马克思"));
        courses1.add(new Course("近代史"));
        courses1.add(new Course("高数"));
        courses2.add(new Course("企业管理"));
        courses2.add(new Course("计算机网络"));
        courses2.add(new Course("大学英语"));
        student1.setName("张三");
        student2.setName("李四");
        student1.setCourseList(courses1);
        student2.setCourseList(courses2);
        List<Student> students = new ArrayList<>();
        students.add(student1);
        students.add(student2);

使用 flatMap。

        Observable.fromIterable(students)
                .flatMap(new Function<Student, ObservableSource<Course>>() {
                    @Override
                    public ObservableSource<Course> apply(Student student) throws Throwable {
                        return Observable.fromIterable(student.getCourseList());
                    }
                })
                .subscribe(new Consumer<Course>() {
                    @Override
                    public void accept(Course course) throws Throwable {
                        Log.d("TAG", course.getName());
                    }
                });

这里的 fromIterable 属于一个创建操作符,如果不使用,相当于如下代码。

        Observable.create(new ObservableOnSubscribe<Student>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Student> emitter) throws Throwable {
                emitter.onNext(student1);
                emitter.onNext(student2);
            }
        }).flatMap(new Function<Student, ObservableSource<Course>>() {
            @Override
            public ObservableSource<Course> apply(Student student) throws Throwable {
                return Observable.create(new ObservableOnSubscribe<Course>() {
                    @Override
                    public void subscribe(@NonNull ObservableEmitter<Course> emitter) throws Throwable {
                        for (Course course : student.getCourseList()) {
                            emitter.onNext(course);
                        }
                    }
                });
            }
        }).subscribe(new Consumer<Course>() {
            @Override
            public void accept(Course course) throws Throwable {
                Log.d("TAG", course.getName());
            }
        });

3.2.3、concatMap

注:此模块测试出现问题:不知道为什么打印不出全部数据,见下面的打印结果。

concatMap 操作符功能与 flatMap 操作符一致;不过,它解决了 flatMap 交叉问题,提供了一种能够把发射的值连续在一起的函数,而不是合并它们,保证了原始的发送顺序。使用方法和 flatMap 一样,只需要把 flatMap 改成 concatMap。

        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
            }
        }).concatMap(new Function<Integer, ObservableSource<?>>() {
            @Override
            public ObservableSource<?> apply(Integer integer) throws Throwable {
                return Observable.create(new ObservableOnSubscribe<String>() {
                    @Override
                    public void subscribe(@NonNull ObservableEmitter<String> emitter) throws Throwable {
                        emitter.onNext(integer + "-1");
                        emitter.onNext(integer + "-2");
                        emitter.onNext(integer + "-3");
                    }
                }).delay(5, TimeUnit.SECONDS);
            }
        }).cast(String.class).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Throwable {
                Log.d("TAG", s);
            }
        });

在这里插入图片描述
3.2.4、flatMapIterable

flatMapIterable 操作符可以将数据包装成 Iterable,我们可以在 Iterable 中对数据进行处理。

        Observable.just(1, 2, 3)
                .flatMapIterable(new Function<Integer, Iterable<Integer>>() {
                    @Override
                    public Iterable<Integer> apply(Integer integer) throws Throwable {
                        List<Integer> list = new ArrayList<>();
                        list.add(integer + 1);
                        return list;
                    }
                })
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Throwable {
                        Log.d("TAG", integer.toString());
                    }
                });

在这里插入图片描述
3.2.4、buffer

buffer 操作符将源 Observable 变换为一个新的 Observable,这个新的 Observable 每次发射一组列表值而不是一个一个发射。在下面的例子中,buffer(3) 表示缓存容量为 3,即每次发送 3 个数据。

        Observable.just(1, 2, 3, 4, 5, 6)
                .buffer(3)
                .subscribe(new Consumer<List<Integer>>() {
                    @Override
                    public void accept(List<Integer> integers) throws Throwable {
                        for (Integer integer : integers) {
                            Log.d("TAG", integer.toString());
                        }
                        Log.d("TAG", "----------------");
                    }
                });

在这里插入图片描述

3.2.5、window

和 buffer 操作符类似,只不过 window 操作符发射的是 Observable 而不是数据列表。如下代码。

        Observable.just(1, 2, 3, 4, 5, 6)
                .window(3)
                .subscribe(new Consumer<Observable<Integer>>() {
                    @Override
                    public void accept(Observable<Integer> integerObservable) throws Throwable {
                        integerObservable.subscribe(new Consumer<Integer>() {
                            @Override
                            public void accept(Integer integer) throws Throwable {
                                Log.d("TAG", integer.toString());
                            }
                        });
                        Log.d("TAG", "------------");
                    }
                });

在这里插入图片描述

3.2.6、groupBy

参考博客

groupBy 操作符用于分组元素,将源 Observable 变换成一个发射 Observables 的新的 Observable,Observables 中的每一个 Observable 都发射一组指定的数据。

我的理解,给每一个Observable 发射的数据都指定一个标签 key。例如给 “一条数据” 指定一个 key 为 Integer 类型,值为 5,最后打印 key 值。

        Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> emitter) throws Throwable {
                emitter.onNext("一条数据");
            }
        }).groupBy(new Function<String, Integer>() {
            @Override
            public Integer apply(String s) throws Throwable {
                return 5;
            }
        }).subscribe(new Consumer<GroupedObservable<Integer, String>>() {
            @Override
            public void accept(GroupedObservable<Integer, String> integerStringGroupedObservable) throws Throwable {
                Log.d("TAG", integerStringGroupedObservable.getKey().toString());
            }
        });

在这里插入图片描述
再看一个例子,每个学生都有姓名和评价等级,分为 S、A、B 三个等级,现在根据学生的等级进行分组,最后打印出评价为 S 级别的学生姓名。首先是实体类。

public class Student {
    private String name;
    private String level;

    public Student(String name, String level) {
        this.name = name;
        this.level = level;
    }

    public String getName() {
        return name;
    }

    public String getLevel() {
        return level;
    }
}

初始化数据。

        Student stu1 = new Student("学生1", "B");
        Student stu2 = new Student("学生2", "S");
        Student stu3 = new Student("学生3", "S");
        Student stu4 = new Student("学生4", "A");
        Student stu5 = new Student("学生5", "A");
        Student stu6 = new Student("学生6", "S");
        Student stu7 = new Student("学生7", "B");
        Student stu8 = new Student("学生8", "A");
        Student stu9 = new Student("学生9", "B");

进行分组,并打印评价为 S 的学生姓名。

        Observable.just(stu1, stu2, stu3, stu4, stu5, stu6, stu7, stu8, stu9)
                .groupBy(new Function<Student, String>() {
                    @Override
                    public String apply(Student student) throws Throwable {
                        return student.getLevel();
                    }
                })
                .subscribe(new Consumer<GroupedObservable<String, Student>>() {
                    @Override
                    public void accept(GroupedObservable<String, Student> stringStudentGroupedObservable) throws Throwable {
                        String key = stringStudentGroupedObservable.getKey();
                        switch (key) {
                            case "S":
                                stringStudentGroupedObservable.subscribe(new Consumer<Student>() {
                                    @Override
                                    public void accept(Student student) throws Throwable {
                                        Log.d("TAG", student.getName());
                                    }
                                });
                                break;
                        }
                    }
                });

在这里插入图片描述

3.3、过滤操作符

参考博客,关于众多过滤操作符写的很详细

过滤操作符用于过滤和选择 Observable 发射的数据序列,让 Observable 只发射满足我们条件的数据。过滤操作符有 filter、elementAt、distinct、skip、take、skipLast、takeLast、ignoreElements、throttleFirst、sample、debounce 和 throttleWithTimeout 等。

3.3.1、filter

filter 操作符是对源 Observable 产生的结果自定义规则进行过滤,只有满足条件的结果才会提交给订阅者。

        Observable.just(1, 2, 3, 4, 5)
                .filter(new Predicate<Integer>() {
                    @Override
                    public boolean test(Integer integer) throws Throwable {
                        return integer > 2;
                    }
                })
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Throwable {
                        Log.d("TAG", integer.toString());
                    }
                });

在这里插入图片描述
3.3.2、elementAt

elementAt 操作符用来返回指定位置的数据,也可以指定默认值。

        Observable.just(1, 2, 3, 4, 5)
                .elementAt(2)
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Throwable {
                        Log.d("TAG", integer.toString());
                    }
                });

在这里插入图片描述
3.3.3、distinct

distinct 操作符用来去重,其只允许还没有发射过的数据项通过。关于 distinct 操作符还有其他几个,参考博客,写的很详细。

        Observable.just(1, 2, 3, 4, 5, 5, 4, 3, 2, 1)
                .distinct()
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Throwable {
                        Log.d("TAG", integer.toString());
                    }
                });

在这里插入图片描述

3.3.4、skip、take

skip 操作符将源 Observable 发射的数据过滤掉前 n 项;而 take 操作符则只取前 n 项;另外还有 skipLast 和 takeLast 操作符。则是从后面进行过滤操作。

        Observable.just(1, 2, 3, 4, 5)
                .skip(2)
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Throwable {
                        Log.d("TAG", integer.toString());
                    }
                });
                
        Observable.just(1, 2, 3, 4, 5)
                .take(2)
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Throwable {
                        Log.d("TAG", integer.toString());
                    }
                });

在这里插入图片描述
在这里插入图片描述

3.3.5、ginoreElements

不发射任何数据,只发射Observable的终止通知。

        Observable.just(1, 2, 3, 4, 5)
                .ignoreElements()
                .subscribe(new CompletableObserver() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        Log.d("TAG", "onSubscribe");
                    }

                    @Override
                    public void onComplete() {
                        Log.d("TAG", "onComplete");
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        Log.d("TAG", "onError");
                    }
                });

在这里插入图片描述
3.3.6、throttleFist

参考博客

throttleFirst 操作符会定期发射在设定时间段内源 Observable 发射的第一个数据,throttleFirst 操作符默认在 computation 调度器上执行(调度器后面介绍)。

每个 100ms 发射一个数据。throttleFist 操作符设定的时间为 200ms,因此,它会发射每个 200ms 内的第一个数据。

        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
                for (int i = 0; i < 10; i++) {
                    emitter.onNext(i);
                    Thread.sleep(100);
                }
                emitter.onComplete();
            }
        }).throttleFirst(200, TimeUnit.MILLISECONDS).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Throwable {
                Log.d("TAG", integer.toString());
            }
        });

在这里插入图片描述
3.3.7、sample

和 throttleFist 类似,不过 sample 操作符不是发射第一个数据,而是发射在设定时间段内源 Observable 发射的最近一个数据。

        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
                for (int i = 0; i < 10; i++) {
                    emitter.onNext(i);
                    Thread.sleep(100);
                }
            }
        }).sample(200, TimeUnit.MILLISECONDS).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Throwable {
                Log.d("TAG", integer.toString());
            }
        });

在这里插入图片描述
3.3.8、throttleWithTimeout

通过时间来限流。设定一个时间,在源 Observable 每次发射出来一个数据后就会进行计时,如果计时结束前源 Observable 有数据发射出来,这个数据会被丢弃,同时 throttleWithTimeout 重新开始计时。如果每次都是在计时结束前发射数据,那么这个限流就会走向极端:只发射最后一个数据。默认在 computation 调度器上执行。

        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
                emitter.onNext(0);
                emitter.onNext(1);
                Thread.sleep(50);
                emitter.onNext(2);
                Thread.sleep(100);
                emitter.onNext(3);
                Thread.sleep(100);
                emitter.onComplete();
            }
        }).throttleWithTimeout(100, TimeUnit.MILLISECONDS).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Throwable {
                Log.d("TAG", integer.toString());
            }
        });

在这里插入图片描述

3.4、组合操作符

组合操作符可以同时处理多个 Observable 来创建我们所需要的 Observable。组合操作符有 stratWith、merge、concat、zip、combineLastest、join 和 switch 等。

3.4.1、startWith

参考博客

如果你想要一个 Observable 在发射数据之前先发射一个指定的数据或者数据序列(可以是单个数据、数组、列表,Observable 中的数据),可以使 用 StartWith 操作符。

        Observable.just(1, 2, 3)
                .startWithItem(999)
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Throwable {
                        Log.d("TAG", integer.toString());
                    }
                });

        Log.d("TAG", "-----------------------");
        Observable.just(1, 2, 3)
                .startWith(Observable.just(4, 5, 6))
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Throwable {
                        Log.d("TAG", integer.toString());
                    }
                });

        Log.d("TAG", "-----------------------");
        Observable.just(1, 2, 3)
                .startWithArray(4, 5, 6)
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Throwable {
                        Log.d("TAG", integer.toString());
                    }
                });

在这里插入图片描述

3.4.2、merge

merge 操作符将多个 Observable 合并到一个 Observable 中进行发射,merge 可能会让合并的 Observable 发射的数据交错。

        Observable<Integer> obs1 = Observable.just(1, 2, 3).subscribeOn(Schedulers.io());
        Observable<Integer> obs2 = Observable.just(4, 5, 6);
        Observable.merge(obs1, obs2).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Throwable {
                Log.d("TAG", integer.toString());
            }
        });

在这里插入图片描述
3.4.3、concat

将多个 Observable 发射的数据进行合并发射。oncat 严格按照顺序发射数据,前一个 Observable 没发射完成是不会发射后一个 Observable 的数据的。

        Observable<Integer> obs1 = Observable.just(1, 2, 3).subscribeOn(Schedulers.io());
        Observable<Integer> obs2 = Observable.just(4, 5, 6);
        Observable.concat(obs1, obs2).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Throwable {
                Log.d("TAG", integer.toString());
            }
        });

在这里插入图片描述
3.4.4、zip

参考博客

zip 操作符合并两个或多个 Observable 发射出的数据项,根据指定的函数变换它们,并发射一个新值。

        Observable<Integer> obs1 = Observable.just(1, 2, 3).subscribeOn(Schedulers.io());
        Observable<String> obs2 = Observable.just("a", "b", "c");
        Observable.zip(obs1, obs2, new BiFunction<Integer, String, String>() {
            @Override
            public String apply(Integer integer, String s) throws Throwable {
                return integer + s;
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Throwable {
                Log.d("TAG", s);
            }
        });

在这里插入图片描述

3.4.5、combineLastest

combineLatest 操作符可以结合多个 Observable,可以接收 2-9 个Observable对象, 在其中原始 Observables 的任何一个发射了一条数据时, CombineLatest 使用一个函数结合它们最近发射的数据,然后发射这个函数的返回值。此外combineLatest 操作符还有一些接收 Iterable , 数组方式的变体,以及其他指定参数 combiner、bufferSize、和combineLatestDelayError 方法等变体。

        Observable<Integer> obs1 = Observable.range(0, 3).subscribeOn(Schedulers.io());
        Observable<String> obs2 = Observable.just("a", "b", "c");
        Observable.combineLatest(obs1, obs2, new BiFunction<Integer, String, String>() {
            @Override
            public String apply(Integer integer, String s) throws Throwable {
                return integer + s;
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Throwable {
                Log.d("TAG", s);
            }
        });

在这里插入图片描述

3.5、辅助操作符

辅助操作符可以帮助我们更加方便地处理 Observable。辅助操作符包括 delay、DO、subscribeOn、observeOn、timeout、materialize、dematerialize、timeInterval、timestamp 和 to 等。

3.5.1、delay

参考博客

延迟一段指定的时间再发射来自Observable的发射物。

Delay 操作符让原始 Observable 在发射每项数据之前都暂停一段指定的时间段。效果是Observable发射的数据项在时间上向前整体平移了一个增量。(没太理解这句话)

        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
            }
        }).delay(3, TimeUnit.SECONDS).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Throwable {
                Log.d("TAG", integer.toString());
            }
        });

延迟 3 秒后打印数据。
在这里插入图片描述

3.5.2、Do

参考博客

Do 系列操作符就是为原始 Observable 的生命周期事件注册一个回调,当 Observable 的某个事件发生时就会调用这些回调。RxJava 中有很多 Do 系列操作符,如下所示。

  • doOnSubscribe(Consumer onSubscribe):一旦有观察者订阅了Observable,就会被调用。
  • doOnLifecycle(Consumer onSubscribe, Action onDispose): 在观察者订阅产生和解除时被调用。
  • doOnNext(Consumer onNext):在 Observable 每次发射数据前被调用。
  • doOnEach(Observer observer): 在 Observable 调用观察者的所有通知前被调用。
  • doAfterNext(Consumer onAfterNext):在 Observable 调用OnNext通知(数据发射通知)之后被调用。
  • doOnError(Consumer onError):注册一个动作,当它的 Observable 由于异常终止调用 onError 时会被调用。
  • doOnTerminate(Action onTerminate): 当Observable终止之前会被调用,无论是正常还是异常终止。
  • doAfterTerminate(Action onFinally): 当Observable终止之后会被调用,无论是正常还是异常终止。
  • doOnComplete(Action onComplete):Observable正常终止调用 onCompleted 时会被调用。
  • doFinally(Action onFinally):Observable终止之后会被调用,无论是正常还是异常终止,但是优先于 doAfterTerminate。
  • doOnDispose(Action onDispose):在观察者调用Disposable的dispose()方法时被调用。
        Observable.just(1, 2, 3)
                .doOnNext(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Throwable {
                        Log.d("doOnNext", integer.toString());
                    }
                })
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Throwable {
                        Log.d("subscribe", integer.toString());
                    }
                });

在这里插入图片描述
3.5.3、subscribeOn、onbserveOn

subscribeOn 操作符用于指定 Observable 自身在哪个线程上运行。如果 Observable 需要执行耗时操作,一般可以让其在新开的一个子线程上运行。observerOn 用来指定 Observer 所运行的线程,也就是发射出的数据在哪个线程上使用。一般情况下会指定在主线程中运行,这样就可以更改 UI。

subscribeOn(Schedulers.newThread()) 表示 Observable 运行在新开的线程,observeOn(AndroidSchedulers.mainThread()) 表示运行在主线程。其中 AndroidSchedulers 是 RxAndroid 库提供的 Scheduler,Scheduler 后面会介绍。

        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
                Log.d("Observable", Thread.currentThread().getName());
                emitter.onNext(1);
                emitter.onComplete();
            }
        }).subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Throwable {
                        Log.d("Observer", Thread.currentThread().getName() + integer);
                    }
                });

在这里插入图片描述
3.5.4、timeout

如果原始 Observable 过了指定的一段时长没有发射任何数据,timeout 操作符会以一个 onError 通知终止这个 Observable,或者继续执行一个备用的 Observable 。

timeout 有很多变体,这里介绍其中的一种,它在超时时会切换到使用一个指定的备用的 Observable,而不是发送错误通知。默认在 computation 调度器上执行。

timeout(long timeout, @NonNull TimeUnit unit, @NonNull ObservableSource<? extends T> fallback)

如果 Observable 在 200ms 这段时长没有发射数据,就会切换到 Observable.just(10,11)。

        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
                emitter.onNext(1);
                emitter.onNext(2);
                Thread.sleep(1000);
                emitter.onNext(3);
                emitter.onComplete();
            }
        }).timeout(200, TimeUnit.MILLISECONDS, Observable.just(10, 11)).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Throwable {
                Log.d("TAG", integer.toString());
            }
        });

在这里插入图片描述

3.6、错误处理操作符

RxJava 在错误出现的时候就会调用 Subscriber 的 onError 方法将错误分发出去,由 Subscriber 自己来处理错误。但是如果每个 Subscriber 都处理一遍的话,工作量就有点大了,这时候可以使用错误处理操作符。错误处理操作符有 catch 和 retry。

3.6.1、catch

参考博客

catch 操作符拦截原始 Observable 的 onError 通知,将它替换为其他数据项或数据序列,让产生的 Observable 能够正常终止或者根本不终止。RxJava 将 catch 实现为以下 3 个不同的操作符。

  1. onErrorReturn:返回一个镜像原有Observable行为的新Observable,后者会忽略前者的 onError 调用,不会将错误传递给观察者,作为替代,它会发发射一个特殊的项并调用观察者的 onCompleted 方法。
  2. onErrorResumeNext:返回一个镜像原有Observable行为的新Observable,后者会忽略前者的 onError 调用,不会将错误传递给观察者,作为替代,它会开始另一个指定的备用Observable。
  3. onExceptionResumeNext:与 onErrorResumeNext 类似, onExceptionResumeNext 方法返回一个镜像原有 Observable 行为的新 Observable,也使用一个备用的 Observable,不同的是,如果 onError 收到的 Throwable 不是一个 Exception ,它会将错误传递给观察者的 onError 方法,不会使用备用的 Observable。

这里拿 onErrorReturn 举例,代码如下。

        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onError(new Throwable("Throwable"));
                emitter.onNext(3);
                emitter.onComplete();
            }
        }).onErrorReturn(new Function<Throwable, Integer>() {
            @Override
            public Integer apply(Throwable throwable) throws Throwable {
                return 999;
            }
        }).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Throwable {
                Log.d("TAG", integer.toString());
            }
        });

在这里插入图片描述
3.6.2、retry

参考博客

如果原始 Observable 遇到错误,重新订阅它期望它能正常终止。

Retry 操作符不会将原始 Observable 的 onError 通知传递给观察者,它会订阅这个Observable,再给它机会无错误地完成它的数据序列。 Retry 总是传递 onNext 通知给观察者,由于重新订阅,可能会造成数据项重复情况。

  1. retry():无论收到多少次 onError 通知,都会继续订阅并发射原始Observable。
    注意: 因为如果遇到异常,将会无条件的重新订阅原始的Observable,直到没有异常的发射全部的数据序列为止。所以如果你的异常发生后重新订阅也不会恢复正常的话,会一直订阅下去,有内存泄露的风险。
  2. retry(long times):接受单个 count 参数的 retry 会最多重新订阅指定的次数,如果次数超了,它不会尝试再次订阅,它会把最新的一个 onError 通知传递给它的观察者。
  3. retry(Predicate predicate):接受一个谓词函数作为参数,这个函数的两个参数是:重试次数和导致发射 onError 通知的 Throwable 。这个函数返回一个布尔值,如果返回 true , retry 应该再次订阅和镜像原始的Observable,如果返回 false , retry 会将最新的一个 onError 通知传递给它的观察者。
  4. retry(long times, Predicate predicate):遇到异常后最多重新订阅 times 次,每次重新订阅经过函数 predicate 最终判断是否继续重新订阅,如果 times 到达上限或者 predicate 返回 false 中任意一个最先满足条件,都会终止重新订阅,retry 会将最新的一个 onError 通知传递给它的观察者。
  5. retry(BiPredicate<Integer, Throwable> predicate):遇到异常时,通过函数 predicate 判断是否重新订阅源Observable,并且通过参数 Integer 传递给 predicate 重新订阅的次数,retry 会将最新的一个 onError 通知传递给它的观察者。
  6. retryUntil(BooleanSupplier stop):重试重新订阅,直到给定的停止函数 stop 返回 true,retry 会将最新的一个 onError 通知传递给它的观察者。
  7. retryWhen(Function<Observable, ObservableSource> handler):retryWhen 和 retry 类似,区别是, retryWhen 将 onError 中的 Throwable 传递给一个函数,这个函数产生另一个 Observable, retryWhen 观察它的结果再决定是不是要重新订阅原始的 Observable。如果这个Observable 发射了一项数据,它就重新订阅,如果这个 Observable 发射的是 onError 通知,它就将这个通知传递给观察者然后终止。

这里以 retry(long times) 举例,代码如下。

        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onError(new Throwable("Throwable"));
                emitter.onNext(3);
                emitter.onComplete();
            }
        }).retry(2).subscribe(new Observer<Integer>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                Log.d("TAG", "onSubscribe");
            }

            @Override
            public void onNext(@NonNull Integer integer) {
                Log.d("TAG", "onNext:"+integer);
            }

            @Override
            public void onError(@NonNull Throwable e) {
                Log.d("TAG", "onError:" + e.getMessage());
            }

            @Override
            public void onComplete() {
                Log.d("TAG", "onComplete");
            }
        });

在这里插入图片描述

3.6、条件操作符和布尔操作符

条件操作符和布尔操作符可用于根据条件发射或变换 Observable,或者对它们做布尔运算。

3.6.1、布尔操作符

参考博客

布尔操作符有 all、contains、isEmpty、exists 和 sequenceEqual。

  • all:根据一个函数对源 Observable 发射的所有数据进行判断,最终返回的结果就是这个判断结果。这个函数使用发射的数据作为参数,内部判断所有的数据是否满足我们定义好的判断条件。如果全部都满足则返回 true,否则就返回 false。
        Observable.just(1, 2, 3, 4, 5)
                .all(new Predicate<Integer>() {
                    @Override
                    public boolean test(Integer integer) throws Throwable {
                        Log.d("all", integer.toString());
                        return integer < 3;
                    }
                }).subscribe(new Consumer<Boolean>() {
            @Override
            public void accept(Boolean aBoolean) throws Throwable {
                Log.d("TAG", aBoolean.toString());
            }
        });

在这里插入图片描述

  • contains:用来判断源 Observable 所发射的数据是否包含某一个数据。如果包含该数据,会返回 true;如果源 Observable 已经结束了却还没有发射这个数据,则返回 false。
        Observable.just(1, 2, 3, 4, 5)
                .contains("张三").subscribe(new Consumer<Boolean>() {
            @Override
            public void accept(Boolean aBoolean) throws Throwable {
                Log.d("TAG", aBoolean.toString());
            }
        });

在这里插入图片描述

  • isEmpty:判断原始 Observable 是否发射了数据项,如果原始 Observable 发射了数据,将发射 false,否则发射 true。
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
                emitter.onComplete();
            }
        }).isEmpty().subscribe(new Consumer<Boolean>() {
            @Override
            public void accept(Boolean aBoolean) throws Throwable {
                Log.d("TAG", aBoolean.toString());
            }
        });

在这里插入图片描述

3.6.2、条件操作符

参考博客

条件操作符有 amb、defaultIfEmpty、skipUntil、skipWhile、takeUntil 和 takeWhile 等。

  • amb:对于给定两个或多个 Observable,它只发射首先发射数据或通知的那个 Observable 的所有数据。
        Observable<Integer> obs1 = Observable.just(1, 2, 3).delay(2, TimeUnit.SECONDS);
        Observable<Integer> obs2 = Observable.just(4, 5, 6);
        List<Observable<Integer>> obsList = new ArrayList<>();
        obsList.add(obs1);
        obsList.add(obs2);
        Observable.amb(obsList).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Throwable {
                Log.d("TAG", integer.toString());
            }
        });

在这里插入图片描述

  • defaultEmpty:发射来自原始 Observable 的数据。如果原始 Observable 没有发射数据,就发射一个默认数据。
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
                emitter.onComplete();
            }
        }).defaultIfEmpty(3).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Throwable {
                Log.d("TAG", integer.toString());
            }
        });

在这里插入图片描述

3.7、转换操作符

转换操作符用来将 Observable 转换为另一个对象或数据结构,转换操作符有 toList、toSortedList、toMap、toMultiMap 等。

3.7.1、toList

将发射多项数据且为每一项数据调用 onNext 方法的 Observable 发射的多项数据组合成一个 List,然后调用一次 onNext 方法传递整个列表。

        Observable.just(1, 2, 3).toList().subscribe(new Consumer<List<Integer>>() {
            @Override
            public void accept(List<Integer> integers) throws Throwable {
                for (Integer in : integers) {
                    Log.d("TAG", in.toString());
                }
            }
        });

在这里插入图片描述
3.7.2、toSortedList

类似于 toList 操作符,不同的是,它会对产生的列表排序,默认是自然升序。如果发射的数据项没有实现 Comparable 接口,会抛出一个异常。这时候可以使用 toSortedList(@NonNull Comparator<? super T> comparator) 变体,传递的函数参数会比较两个数据项。

        Observable.just(3, 1, 2).toSortedList().subscribe(new Consumer<List<Integer>>() {
            @Override
            public void accept(List<Integer> integers) throws Throwable {
                for (Integer in : integers) {
                    Log.d("TAG", in.toString());
                }
            }
        });

在这里插入图片描述

3.7.2、toMap

收集原始 Observable 发射的所有数据项到一个 Map(默认是 HashMap),然后发射这个 Map。你可以提供一个用于生成 Map 的 key 的函数,也可以提供一个函数转换数据项到 Map 存储的值(默认数据项本身就是值)。

类似于在变换操作符中的 groupBy。

        Student stu1 = new Student("张三", "B");
        Student stu2 = new Student("李四", "A");
        Student stu3 = new Student("王五", "S");
        Observable.just(stu1, stu2, stu3).toMap(new Function<Student, String>() {
            @Override
            public String apply(Student student) throws Throwable {
                return student.getLevel();
            }
        }).subscribe(new Consumer<Map<String, Student>>() {
            @Override
            public void accept(Map<String, Student> stringStudentMap) throws Throwable {
                Log.d("TAG", stringStudentMap.get("S").getName());
            }
        });

在这里插入图片描述

四、RxJava 的线程控制

参考博客

1、 内置的 Scheduler

如果我们不指定线程,默认是在调用 subscribe 方法的线程上进行回调的。如果我们想切换线程,就需要使用 Scheduler。RxJava 已经内置了如下 Scheduler。

  • Schedulers.io( ):
    用于IO密集型的操作,例如读写 SD卡文件,查询数据库,访问网络等,具有线程缓存机制,在此调度器接收到任务后,先检查线程缓存池中,是否有空闲的线程,如果有,则复用,如果没有则创建新的线程,并加入到线程池中,如果每次都没有空闲线程使用,可以无上限的创建新线程。

  • Schedulers.newThread( ):
    在每执行一个任务时创建一个新的线程,不具有线程缓存机制,因为创建一个新的线程比复用一个线程更耗时耗力,虽然使用Schedulers.io( )的地方,都可以使用Schedulers.newThread( ),但是,Schedulers.newThread( )的效率没有Schedulers.io( )高。

  • Schedulers.computation():
    用于CPU 密集型计算任务,即不会被 I/O 等操作限制性能的耗时操作,例如xml,json文件的解析,Bitmap图片的压缩取样等,具有固定的线程池,大小为CPU的核数。不可以用于I/O操作,因为I/O操作的等待时间会浪费CPU。

  • Schedulers.trampoline():
    在当前线程立即执行任务,如果当前线程有任务在执行,则会将其暂停,等插入进来的任务执行完之后,再将未完成的任务接着执行。

  • Schedulers.single():
    拥有一个线程单例,所有的任务都在这一个线程中执行,当此线程中有任务执行时,其他任务将会按照先进先出的顺序依次执行。

  • Scheduler.from(@NonNull Executor executor):
    指定一个线程调度器,由此调度器来控制任务的执行策略。

  • AndroidSchedulers.mainThread():
    RxAndroid库中提供的Scheduler,在Android UI线程中执行任务,为Android开发定制。

2、 控制线程

使用 subscribeOn 和 observeOn 操作符来控制线程,使用方法在辅助操作符中的 3.5.3 中。

五、RxJava 的使用场景

关于 RxJava,实际有很多可以使用它的场景,这里介绍 RxJava 结合 OkHttp、Retrofit 访问网络及用 RxJava 实现 RxBus。

5.1、RxJava 结合 OkHttp 访问网络

RxJava 结合 Retrofit 访问网络是比较好的搭配,当然 RxJava 结合 OkHttp 访问网络也是可以的。

    implementation 'io.reactivex.rxjava3:rxjava:3.0.4'
    implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
    implementation 'com.squareup.okhttp3:okhttp:4.9.0'
        Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> emitter) throws Throwable {
                Request.Builder requestBuilder = new Request.Builder().url("http://ip.taobao.com/outGetIpInfo?ip=125.84.85.202&accessKey=alibaba-inc");
                requestBuilder.method("GET", null);
                Request request = requestBuilder.build();
                OkHttpClient okHttpClient = new OkHttpClient();
                Call call = okHttpClient.newCall(request);
                call.enqueue(new Callback() {
                    @Override
                    public void onFailure(@NotNull Call call, @NotNull IOException e) {
                        Toast.makeText(getApplicationContext(), "请求失败", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                        String str = response.body().string();
                        emitter.onNext(str);
                        emitter.onComplete();
                    }
                });
            }
        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Throwable {
                        Log.d("TAG", s);
                        Toast.makeText(MainActivity.this, "请求成功", Toast.LENGTH_LONG).show();
                    }
                });

5.2、RxJava 结合 Retrofit 访问网络

继续使用 Retrofit 的例子。

一、配置 gradle

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    implementation 'io.reactivex.rxjava3:rxjava:3.0.4'
    implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    // 需要配置 Retrofit 中的 RxJava 转换器
    implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'

二、请求网络接口

Retrofit 的请求接口返回的是 Call。若结合 RxJava 使用,则需要把 Call 改为 Observable。

public interface IpService {
    @FormUrlEncoded
    @POST("outGetIpInfo")
    Observable<IpModel> getIpMsg(@Field("ip") String ip, @Field("accessKey") String accessKey);
}

三、请求方法

为了能用 RxJava 提供的方法对请求网络的回调进行处理,注意需要调用 addCallAdapterFactory 方法。

    private void postIpInformation(String ip) {
        String url = "http://ip.taobao.com/";
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(url)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
                .build();
        IpService ipService = retrofit.create(IpService.class);
        Observable<IpModel> observable = ipService.getIpMsg(ip, "alibaba-inc");
        observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<IpModel>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        Log.d("TAG", "onSubscribe");
                    }

                    @Override
                    public void onNext(@NonNull IpModel ipModel) {
                        String country = ipModel.getData().getCountry();
                        Toast.makeText(MainActivity.this, country, Toast.LENGTH_LONG).show();
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        Log.d("TAG", "onError");
                    }

                    @Override
                    public void onComplete() {
                        Log.d("TAG", "onComplete");
                    }
                });

调用

        postIpInformation("125.84.85.202");

四、请求返回数据格式封装

对于日常开发来说,返回的 code 值和 message 值一般是固定的,而 data 值则是不断变化的。可以提取一个数据格式的基本类。

public class BaseResult<T> {
    private int code;
    private T data;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}
public class DataBean {
    private String ip;
    private String country;
    private String area;
    private String region;
    private String city;
    private String county;
    private String isp;
    private String country_id;
    private String area_id;
    private String region_id;
    private String city_id;
    private String county_id;
    private String isp_id;

    ...省略 get set 方法...
}

修改请求接口和请求代码。

public interface IpService {
    @FormUrlEncoded
    @POST("outGetIpInfo")
    Observable<BaseResult<DataBean>> getIpMsg(@Field("ip") String ip, @Field("accessKey") String accessKey);
}
    private void postIpInformation(String ip) {
        String url = "http://ip.taobao.com/";
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(url)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
                .build();
        IpService ipService = retrofit.create(IpService.class);
        Observable<BaseResult<DataBean>> observable = ipService.getIpMsg(ip, "alibaba-inc");
        observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<BaseResult<DataBean>>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        Log.d("TAG", "onSubscribe");
                    }

                    @Override
                    public void onNext(@NonNull BaseResult<DataBean> dataBeanBaseResult) {
                        String country = dataBeanBaseResult.getData().getCountry();
                        Toast.makeText(MainActivity.this, country, Toast.LENGTH_LONG).show();
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        Log.d("TAG", "onError");
                    }

                    @Override
                    public void onComplete() {
                        Log.d("TAG", "onComplete");
                    }
                });

五、取消请求

RxJava 在订阅了事件后没有及时解除订阅,导致在 Activity 或 Fragment 销毁后仍然占有内存,无法释放,就会产生内存泄漏。

如果只使用 Retrofit,可以用 Call 的 cancel 方法来取消请求。如果结合 RxJava,在 1.2.1 中和 1.3.1 中有说明,可以通过记录 onSubscribe 方法返回的 Disposable 或 Subscription 来取消,Disposable 调用 dispose 方法,Subscription 调用 cancel 方法。

       private Disposable disposable;
          ...
                   @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        Log.d("TAG", "onSubscribe");
                        disposable = d;
                    }
         ...
      disposable.dispose();

如果想取消多个请求,可以使用 CompositeDisposable 类。

    private CompositeDisposable compositeDisposable = new CompositeDisposable();
      ...
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        Log.d("TAG", "onSubscribe");
                        compositeDisposable.add(d);
                    }
      ...
    compositeDisposable.clear();

5.3、用 RxJava 实现 RxBus

事件总线框架 EventBus 都不陌生,可以用 RxJava 来替代。

参考博客

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值