操作符字典
一、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 基本实现
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
只会发送最后一个数据,这里只会打印 “孙七”。需要调用 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
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 个不同的操作符。
- onErrorReturn:返回一个镜像原有Observable行为的新Observable,后者会忽略前者的 onError 调用,不会将错误传递给观察者,作为替代,它会发发射一个特殊的项并调用观察者的 onCompleted 方法。
- onErrorResumeNext:返回一个镜像原有Observable行为的新Observable,后者会忽略前者的 onError 调用,不会将错误传递给观察者,作为替代,它会开始另一个指定的备用Observable。
- 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 通知给观察者,由于重新订阅,可能会造成数据项重复情况。
- retry():无论收到多少次 onError 通知,都会继续订阅并发射原始Observable。
注意: 因为如果遇到异常,将会无条件的重新订阅原始的Observable,直到没有异常的发射全部的数据序列为止。所以如果你的异常发生后重新订阅也不会恢复正常的话,会一直订阅下去,有内存泄露的风险。 - retry(long times):接受单个 count 参数的 retry 会最多重新订阅指定的次数,如果次数超了,它不会尝试再次订阅,它会把最新的一个 onError 通知传递给它的观察者。
- retry(Predicate predicate):接受一个谓词函数作为参数,这个函数的两个参数是:重试次数和导致发射 onError 通知的 Throwable 。这个函数返回一个布尔值,如果返回 true , retry 应该再次订阅和镜像原始的Observable,如果返回 false , retry 会将最新的一个 onError 通知传递给它的观察者。
- retry(long times, Predicate predicate):遇到异常后最多重新订阅 times 次,每次重新订阅经过函数 predicate 最终判断是否继续重新订阅,如果 times 到达上限或者 predicate 返回 false 中任意一个最先满足条件,都会终止重新订阅,retry 会将最新的一个 onError 通知传递给它的观察者。
- retry(BiPredicate<Integer, Throwable> predicate):遇到异常时,通过函数 predicate 判断是否重新订阅源Observable,并且通过参数 Integer 传递给 predicate 重新订阅的次数,retry 会将最新的一个 onError 通知传递给它的观察者。
- retryUntil(BooleanSupplier stop):重试重新订阅,直到给定的停止函数 stop 返回 true,retry 会将最新的一个 onError 通知传递给它的观察者。
- 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 来替代。