前言
首先,感谢以下作者分享自己对于RxJava的理解
给 Android 开发者的 RxJava 详解
针对RxJava1.×,入门必备
RxJava2 只看这一篇文章就够了 - 掘金
RxJava2的API大全,适合需要使用对应APID时作为资料查看
本文设计源码以及介绍均是基于RxJava2,示例均是为了示例而示例,项目中要使用RxJava,首先在gradle中添加依赖:
implementation 'io.reactivex.rxjava2:rxjava:2.1.4'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
一、RxJava2简介
什么是RxJava
A library for composing asynchronous and event-based programs by using observable sequences.
一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库
引用RxJava Github Readme中的介绍,可能看起来仍然让人感到费解,我的理解是:
使用观察者模式,采用链式编程,基于事件的实现异步的库
到这里,没有使用过RxJava的话,一定还是不知道这个库究竟是做什么的,没关系,我们慢慢道来。首先我们需要知道RxJava究竟解决了什么问题。
RxJava解决了什么问题
即使没有使用过,一定也听说过RxJava,RxJava应用如此广泛,那么它究竟解决了什么问题呢?一个词:异步,但是同样是异步,可以使用的工具有很多,我们为什么偏偏要使用RxJava呢?
为什么使用RxJava
我们知道,Android中实现异步的方式有很多,Handler、AsyncTask、runOnUiThread等,为什么我们就要使用RxJava来实现异步呢?换言之,RxJava相比其他实现异步的方法有什么优势呢?最大的优势就是逻辑清晰。
假设有这样一个需求:界面上有一个自定义的视图 imageCollectorView ,它的作用是显示多张图片,并能使用 add(Bitmap) 方法来任意增加显示的图片。现在需要程序将一个给出的目录数组 File[] folders 中每个目录下的 png 图片都加载出来并显示在 imageCollectorView 中。需要注意的是,由于读取图片的这一过程较为耗时,需要放在后台执行,而图片的显示则必须在 UI 线程执行。常用的实现方式有多种,我这里贴出其中一种:
new Thread(() -> {
for (File folder : folders) {
File[] files = folder.listFiles();
for (File file : files) {
if (file.getName().endsWith(".png")) {
final Bitmap bitmap = getBitmapFromFile(file);
runOnUiThread(() -> imageCollectorView.add(bitmap));
}
}
}
}).start();
而如果使用RxJava,实现方式是这样的:
Observable.fromArray(folders)
.flatMap((Function>) folder -> Observable.fromArray(folder.listFiles()))
.filter(file -> file.getName().endsWith("png"))
.map((Function) file -> getBitmapFromFile(file))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(bitmap -> imageCollectorView.add(bitmap));
一定有人会觉得,这完全没有简洁呀,哪里看出来简洁了,上面所说的简洁只是逻辑简洁,而非代码简洁。
观察一下,你就会发现,使用RxJava,是一条链式调用下来的,完全没有任何嵌套,这种优势在需求变得复杂之后,优势会更加明显,比如我们现在增加一条需求,只需要加载前十张图片,不使用RxJava要怎么去做呢?相信大家都会做,不妨实现去看看,而如果是使用RxJava,修改后的实现如下:
Observable.fromArray(folders)
.flatMap((Function>) folder -> Observable.fromArray(folder.listFiles()))
.filter(file -> file.getName().endsWith("png"))
.map((Function) file -> getBitmapFromFile(file))
.take(LOAD_IMAGE_NUM)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(bitmap -> imageCollectorView.add(bitmap));
可以看到,仅仅只增加了一行代码,且未新增任何嵌套。
所以RxJava最大的优势就是简洁,无论逻辑如何复杂,总是一条链式调用的简洁。
二、基本使用
在分析RxJava的原理之前,我们首先要了解一下观察者模式,如果已经熟知观察者模式,可以跳过这段。
观察者模式
先让我们想象一下生活中一个场景:
读者(观察者)发现一个微信公众号(被观察者)很不错,希望长期关注,于是便关注(注册)了这个微信公众号,当这个微信公众号发布了一篇新的文章,关注了该微信公众号的读者就会接收到通知(被观察者发送通知给注册了的观察者),如果读者不再关注(注销)该微信公众号,就再不会接收到通知了
以上就是一个典型的观察者模式的流程,生活中像这样的场景还有很多,那么什么是观察者模式呢?
概念
引用《Head First设计模式》一书中的原话
观察者模式定义了对象之间一对多的依赖,这样一来,当该对象改变状态时,它的所有依赖者会受到通知并自动更新
——Head First设计模式
以下是观察者模式UML图
观察者模式UML图
我们可以看到,观察者模式首先定义了两个接口类:Observable(被观察者)、Observer(观察者),
Observable接口中包含三个方法
registerObserver()注册
removeObserver()注销
notifyObservers()发送通知
Observer接口中包含一个方法
update()观察者接收到通知后的行为
以上两个接口,很简单,在这里我就不贴代码了,那么实现类要怎么做呢?
以下是实现类的代码
Observable实现类:
public class ConcreteObservable implements Observable {
private static final String TAG = ConcreteObservable.class.getSimpleName();
List observers;
public ConcreteObservable(){
observers = new ArrayList<>();
}
@Override
public void register(Observer observer) {
if (observer == null) {
throw new NullPointerException("observer cannot be null");
}
if (observers.contains(observer)) {
Log.d("TAG", "you have registered this");
} else {
Log.d("TAG", observer.toString() + " register");
observers.add(observer);
}
}
@Override
public void removeObserver(Observer observer) {
if (observer == null) {
throw new NullPointerException("observer cannot be null");
}
if (observers.contains(observer)) {
Log.d("TAG", observer.toString() + " remove");
observers.remove(observer);
} else {
Log.d("TAG", "you have not registered this");
}
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
Observer实现类:
public class TomObserver implements Observer {
private static final String TAG = TomObserver.class.getSimpleName();
@Override
public void update() {
Log.d("TAG", "notify Tom");
}
@Override
public String toString() {
return "Tom";
}
}
public class KittyObserver implements Observer {
@Override
public void update() {
Log.d("TAG", "notify Kitty");
}
@Override
public String toString() {
return "Kitty";
}
}
使用:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Observer tomObserver = new TomObserver(), kittyObserver = new KittyObserver();
Observable observable = new ConcreteObservable();
observable.register(tomObserver);
observable.register(kittyObserver);
observable.notifyObservers();
observable.removeObserver(tomObserver);
observable.notifyObservers();
}
}
打印日志
D/TAG: Tom register
D/TAG: Kitty register
D/TAG: notify Tom
D/TAG: notify Kitty
D/TAG: Tom remove
D/TAG: notify Kitty
观察者模式在RxJava中的应用
RxJava中有四个概念,Observable(被观察者)、Observer(观察者)、subscribe(订阅)、事件,
Observer和Observable通过subscribe方法实现订阅,从而Observable发送事件时,Observer可以收到相关通知。
与标准观察者模式不同的是,RxJava除了onNext(对应标准观察者模式的notifyObservers())事件以外,还有onError()和onComplete(),当Observable发送完一系列onNext()事件后,必须调用onComplete()标志着事件序列的结束,中间如果出现错误,便会走到onError()事件,这两个事件均只会被调用一次,且是相互排斥的,即走到了onComplete()就不会走到onError(),反之亦然。
基本实现
Observable(被观察者)
Observable observable = Observable.create(emitter -> {
emitter.onNext("Hello, observer");
emitter.onComplete();
});
可以看到通过Observable.create()方法创建了Observable对象,方法中传入了ObservableOnSubscribe对象,这个类中使用了泛型,这里的泛型就对应着onNext()事件传入的参数类型,以上例子这里的数据类型是String,在传入的ObservableOnSubscribe对象中,重写了subscribe方法,上述例子发送了一个onNext()事件,又发送了一个onComplete()事件,告诉Observer事件序列结束,不会再有新的onNext()事件。
当然,Observable对象并不止这一种创建方式,RxJava提供了很多相关的API,例如fromArray()、just()等等,暂且按下不表。
Observer(观察者)
Observer observer = new Observer() {
@Override
public void onSubscribe(Disposable d) {
Log.d("TAG", "onSubscribe");
}
@Override
public void onNext(String o) {
Log.d("TAG", o);
}
@Override
public void onError(Throwable e) {
Log.d("TAG", "onError");
}
@Override
public void onComplete() {
Log.d("TAG", "onComplete");
}
};
创建Observer对象需要重写四个方法,可以看到其中三个重写的方法刚好对应三个事件,可以猜测,Observable发送的事件应该是交由对应的方法处理,但是多出来的onSubscribe()方法是做什么的呢?onSubscribe()方法是在Observable发送事件前被调用的,稍后会说到这点。
当然,RxJava中的观察者对象并不止Observer这一个类,RxJava还提供了一些其他的类供实现,例如Consumer等。
subscribe(订阅)
observable.subscribe(observer);
这一步就非常简单,但是会发现这里有个奇怪的地方,正常流程应该是观察者订阅被观察者,但是这里却是被观察者订阅观察者,显然,observer.subscribe(observable)这样的写法更加容易让读者接受
过如果把 API 设计成 observer.subscribe(observable) / subscriber.subscribe(observable) ,虽然更加符合思维逻辑,但对流式 API 的设计就造成影响了,比较起来明显是得不偿失的。
以上引用扔物线的一段话
RxJava中线程控制
有一些读者一定好奇,说了半天,好像也没有看到实现了异步呀,别着急,这就介绍RxJava是如何在这个链式编程中实现异步的。
我们看一下下面的示例代码
Observable
.create((ObservableOnSubscribe) emitter -> {
//模拟网络访问流程
Log.d("TAG", "subscribe " + Thread.currentThread().getName());
Thread.sleep(200);
emitter.onNext("json ");
emitter.onComplete();
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
Log.d("TAG", "onSubscribe " + Thread.currentThread().getName());
}
@Override
public void onNext(String s) {
Log.d("TAG", s + Thread.currentThread().getName());
}
@Override
public void onError(Throwable e) {
Log.d("TAG", "onError " + Thread.currentThread().getName());
}
@Override
public void onComplete() {
Log.d("TAG", "onComplete " + Thread.currentThread().getName());
}
});
以下是日志
D/TAG: onSubscribe main
D/TAG: subscribe RxCachedThreadScheduler-1
D/TAG: json main
D/TAG: onComplete main
我们发现,Observable发送事件的方法是运行在子线程的,而Observer处理事件的方法均是运行在主线程(UI线程),而我们仅仅只是增加了两行代码,就实现了异步编程,是不是很方便呢?但是有一个例外,onSubscribe()方法根据日志打印,是运行在主线程的,那么它真的就是和其他的事件一样,由于增加了两行代码,运行在了主线程吗?我们让这个任务在子线程运行,再看看打印的日志
D/TAG: onSubscribe Thread-4
D/TAG: subscribe RxCachedThreadScheduler-1
D/TAG: json main
D/TAG: onComplete main
由此我们知道,onSubscribe()既不是运行在发送事件的线程,也不是运行在处理事件的线程,而是运行在当前线程,具体这是为什么呢,我们后面会介绍。现在我们先来看一下,增加的两行代码究竟是什么意思呢?
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
subscribeOn(Scheduler scheduler)方法定义了发送事件运行的线程,而observeOn(Scheduler scheduler)方法则是指定处理事件运行的线程,RxJava中也指定了一些可以直接使用的Scheduler
AndroidSchedulers.mainThread()
Android主线程,即UI线程
Schedulers.newThread()
创建一个新的线程
Schedulers.io()
用于 IO 密集型任务,如果异步阻塞 IO 操作。
Schedulers.computation()
用于使用计算任务,如事件循环和回调处理
Schedulers.trampoline()
当前线程
Schedulers.single()
单线程,如果线程中有正在处理的任务,新来的任务会进入等待队列
Schedulers.from(Executor executor)
指定一个线程池
常用Api
创建操作符
1. create()
有什么用
创建一个Observable
怎么用
Observable
.create((ObservableOnSubscribe) emitter -> {
emitter.onNext("1");
emitter.onNext("2");
emitter.onNext("3");
emitter.onComplete();
})
.subscribe((s -> Log.d(TAG, "onNext: " + s)));
日志打印
D/MainActivity: onNext: 1
D/MainActivity: onNext: 2
D/MainActivity: onNext: 3
2. just()
有什么用
传入不超过十个对象,依次发送
怎么用
Observable.just(1, 3, 5)
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "onNext: " + integer);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete");
}
});
日志打印
D/MainActivity: onNext: 1
D/MainActivity: onNext: 3
D/MainActivity: onNext: 5
D/MainActivity: onComplete
3. fromArray()
有什么用
与just()类似,只不过fromArray()可以传入超过10个item,也可以传入数组、集合等
怎么用
Integer[] array = {1, 3, 5};
Observable.fromArray(array)
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "onNext: " + integer);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete");
}
});
日志打印
D/MainActivity: onNext: 1
D/MainActivity: onNext: 3
D/MainActivity: onNext: 5
D/MainActivity: onComplete
注意:这里的数组必须是对象数组,而不能是基本类型数组
4. fromCallable()
有什么用
这里的 Callable 是 java.util.concurrent 中的 Callable,Callable 和 Runnable 的用法基本一致,只是它会返回一个结果值,这个结果值就是发给观察者的。
怎么用
Observable.fromCallable(() -> 1)
.subscribe(integer -> Log.d(TAG, "accept" + integer));
日志打印
D/MainActivity: accept: 1
5. timer()
有什么用
指定时间倒计时结束后,会发送一个0L的值给观察者
怎么用
Observable.timer(5, TimeUnit.SECONDS)
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "onSubscribe");
}
@Override
public void onNext(Long aLong) {
Log.d(TAG, "onNext: " + aLong);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
日志打印
2019-05-20 21:59:42.912 5248-5248/com.danc.calendartext D/MainActivity: onSubscribe
2019-05-20 21:59:47.918 5248-5302/com.danc.calendartext D/MainActivity: onNext: 0
可以看到,onSubscribe之后隔了5s中,接收到onNext事件
6. interval()
有什么用
每隔指定时间发送一个事件,这个事件包含一个数字,从0开始,每次自增1
怎么用
Observable.interval(0, 1, TimeUnit.SECONDS)
.subscribe(aLong -> {
Log.d(TAG, "计时(s): " + aLong);
});
日志打印
2019-05-20 22:03:29.786 5375-5420/com.danc.calendartext D/MainActivity: 计时(s): 0
2019-05-20 22:03:30.786 5375-5420/com.danc.calendartext D/MainActivity: 计时(s): 1
2019-05-20 22:03:31.786 5375-5420/com.danc.calendartext D/MainActivity: 计时(s): 2
2019-05-20 22:03:32.787 5375-5420/com.danc.calendartext D/MainActivity: 计时(s): 3
2019-05-20 22:03:33.786 5375-5420/com.danc.calendartext D/MainActivity: 计时(s): 4
2019-05-20 22:03:34.786 5375-5420/com.danc.calendartext D/MainActivity: 计时(s): 5
转化操作符
1. map()
有什么用
将被观察者发送的数据类型转换为其他类型
怎么用
以下实例将Integer类型转换为String
Observable.just(1, 3, 5)
.map(integer -> "--" + integer)
.subscribe(s -> Log.d(TAG, "accept: " + s));
日志打印
2019-05-20 22:05:58.079 5494-5494/com.danc.calendartext D/MainActivity: accept: --1
2019-05-20 22:05:58.079 5494-5494/com.danc.calendartext D/MainActivity: accept: --3
2019-05-20 22:05:58.079 5494-5494/com.danc.calendartext D/MainActivity: accept: --5
2. flatMap()
有什么用
这个方法可以将事件序列中的元素进行整合加工,返回一个新的被观察者。
怎么用
flatMap() 其实与 map() 类似,但是 flatMap() 返回的是一个 Observerable。现在用一个例子来说明 flatMap() 的用法。
假设一个有一个 Person 类,这个类的定义如下:
public class Person {
private String name;
private List planList = new ArrayList<>();
public Person(String name, List planList) {
this.name = name;
this.planList = planList;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List getPlanList() {
return planList;
}
public void setPlanList(List planList) {
this.planList = planList;
}
}
Person 类有一个 name 和 planList 两个变量,分别代表的是人名和计划清单。
Plan 类的定义如下:
public class Plan {
private String time;
private String content;
private List actionList = new ArrayList<>();
public Plan(String time, String content) {
this.time = time;
this.content = content;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public List getActionList() {
return actionList;
}
public void setActionList(List actionList) {
this.actionList = actionList;
}
}
现在有一个需求就是要将 Person 集合中的每个元素中的 Plan 的 action 打印出来。
首先用 map() 来实现这个需求看看:
Observable.fromIterable(personList)
.map(new Function < Person, List < Plan >> () {
@Override
public List < Plan > apply(Person person) throws Exception {
return person.getPlanList();
}
})
.subscribe(new Observer < List < Plan >> () {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(List < Plan > plans) {
for (Plan plan: plans) {
List < String > planActionList = plan.getActionList();
for (String action: planActionList) {
Log.d(TAG, "==================action " + action);
}
}
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
可以看到 onNext() 用了嵌套 for 循环来实现,如果代码逻辑复杂起来的话,可能需要多重循环才可以实现。
现在看下使用 flatMap() 实现:
Observable.fromIterable(personList)
.flatMap(new Function < Person, ObservableSource < Plan >> () {
@Override
public ObservableSource < Plan > apply(Person person) {
return Observable.fromIterable(person.getPlanList());
}
})
.flatMap(new Function < Plan, ObservableSource < String >> () {
@Override
public ObservableSource < String > apply(Plan plan) throws Exception {
return Observable.fromIterable(plan.getActionList());
}
})
.subscribe(new Observer < String > () {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
Log.d(TAG, "==================action: " + s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
从代码可以看出,只需要两个 flatMap() 就可以完成需求,并且代码逻辑非常清晰。
组合操作符
1. zip()
有什么用
将两个被观察者事件整合发送给观察者,事件数量与两个观察这种事件数量较小的相同
怎么用
Observable.zip(Observable.intervalRange(1, 5, 1, 2, TimeUnit.SECONDS)
.map(aLong -> {
String s1 = "A" + aLong;
Log.d(TAG, "===================A 发送的事件 " + s1);
return s1;
}).subscribeOn(Schedulers.io()),
Observable.intervalRange(1, 6, 1, 1, TimeUnit.SECONDS)
.map(aLong -> {
String s2 = "B" + aLong;
Log.d(TAG, "===================B 发送的事件 " + s2);
return s2;
}).subscribeOn(Schedulers.io()),
(s, s2) -> {
String res = s + s2;
return res;
})
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "===================onSubscribe ");
}
@Override
public void onNext(String s) {
Log.d(TAG, "===================onNext " + s);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "===================onError ");
}
@Override
public void onComplete() {
Log.d(TAG, "===================onComplete ");
}
});
日志打印:
2019-05-20 22:19:10.293 6183-6183/com.danc.calendartext D/MainActivity: ===================onSubscribe
2019-05-20 22:19:11.308 6183-6210/com.danc.calendartext D/MainActivity: ===================A 发送的事件 A1
2019-05-20 22:19:11.308 6183-6209/com.danc.calendartext D/MainActivity: ===================B 发送的事件 B1
2019-05-20 22:19:11.308 6183-6209/com.danc.calendartext D/MainActivity: ===================onNext A1B1
2019-05-20 22:19:12.307 6183-6209/com.danc.calendartext D/MainActivity: ===================B 发送的事件 B2
2019-05-20 22:19:13.307 6183-6210/com.danc.calendartext D/MainActivity: ===================A 发送的事件 A2
2019-05-20 22:19:13.307 6183-6210/com.danc.calendartext D/MainActivity: ===================onNext A2B2
2019-05-20 22:19:13.307 6183-6209/com.danc.calendartext D/MainActivity: ===================B 发送的事件 B3
2019-05-20 22:19:14.308 6183-6209/com.danc.calendartext D/MainActivity: ===================B 发送的事件 B4
2019-05-20 22:19:15.306 6183-6210/com.danc.calendartext D/MainActivity: ===================A 发送的事件 A3
2019-05-20 22:19:15.307 6183-6210/com.danc.calendartext D/MainActivity: ===================onNext A3B3
2019-05-20 22:19:15.307 6183-6209/com.danc.calendartext D/MainActivity: ===================B 发送的事件 B5
2019-05-20 22:19:16.307 6183-6209/com.danc.calendartext D/MainActivity: ===================B 发送的事件 B6
2019-05-20 22:19:17.307 6183-6210/com.danc.calendartext D/MainActivity: ===================A 发送的事件 A4
2019-05-20 22:19:17.308 6183-6210/com.danc.calendartext D/MainActivity: ===================onNext A4B4
2019-05-20 22:19:19.307 6183-6210/com.danc.calendartext D/MainActivity: ===================A 发送的事件 A5
2019-05-20 22:19:19.307 6183-6210/com.danc.calendartext D/MainActivity: ===================onNext A5B5
2019-05-20 22:19:19.307 6183-6210/com.danc.calendartext D/MainActivity: ===================onComplete
功能操作符
1. delay()
有什么用
订阅后,延迟一段时间发送事件
怎么用
Observable.just(1, 3, 5)
.delay(2, TimeUnit.SECONDS)
.subscribe(integer -> Log.d(TAG, "accept: " + integer));
打印日志
2019-05-20 22:24:53.879 6430-6430/com.danc.calendartext D/MainActivity: onSubscribe
2019-05-20 22:24:55.881 6430-6475/com.danc.calendartext D/MainActivity: accept: 1
2019-05-20 22:24:55.881 6430-6475/com.danc.calendartext D/MainActivity: accept: 3
2019-05-20 22:24:55.882 6430-6475/com.danc.calendartext D/MainActivity: accept: 5
从日志可以暗处,订阅之后延迟2s开始发送事件
2. doOnNext()
有什么用
每次收到onNext()事件,先执行doOnNext()
怎么用
Observable.create((ObservableOnSubscribe) e -> {
e.onNext(1);
e.onNext(2);
e.onNext(3);
e.onComplete();
})
.doOnNext(integer -> Log.d(TAG, "doOnNext " + integer))
.subscribe(new Observer < Integer > () {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "onSubscribe ");
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "onNext " + integer);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "onError ");
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete ");
}
});
日志打印
D/MainActivity: onSubscribe
D/MainActivity: doOnNext 1
D/MainActivity: onNext 1
D/MainActivity: doOnNext 2
D/MainActivity: onNext 2
D/MainActivity: doOnNext 3
D/MainActivity: onNext 3
D/MainActivity: onComplete
想要查看更多的RxJava2的API,可以看下面这篇文章。这篇文章更像是查阅的资料,只需要通览了解一遍即可,熟悉常用的API,其余有个印象,需要的时候再查阅
RxJava2 只看这一篇文章就够了 - 掘金
生命周期管理
RxJava固然很好用,但是使用不当,很容易造成内存泄漏。
比如,使用RxJava发布一个订阅后,当Activity被finish,此时订阅逻辑还未完成,如果没有及时取消订阅,就会导致Activity无法被回收,从而引发内存泄漏。
目前,针对以上这种情况,主流的有两种解决方案:
通过封装,手动控制每一次订阅,在合适的时机取消订阅
使用RxLifecycle,关注Fragment、Activity的生命周期,在onDestroy()生命周期中自动取消订阅
手动实现
以下是基于MVP架构封装的
protected CompositeDisposable compositeDisposable;
@UiThread
public void attachView(V view) {
mView = view;
compositeDisposable = new CompositeDisposable();
}
@UiThread
public void detachView() {
mView = null;
if (compositeDisposable != null) {
compositeDisposable.clear();
compositeDisposable = null;
}
}
如何使用
在每次发生订阅关系时,将返回的Disposable实例保存在CompositeDisposable中,在onDestroy()生命周期解除所有的订阅关系
RxLifecycle
1. 添加依赖
在项目中添加以下依赖
implementation 'com.trello.rxlifecycle2:rxlifecycle:2.2.1'
implementation 'com.trello.rxlifecycle2:rxlifecycle-android:2.2.1'
implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.1'
2. 绑定生命周期
RxLifecycle提供了大量的Activity、Fragment以供继承
RxLifecycle支持的Component、
代码如下:
public class MainActivity extends RxAppCompatActivity {
...
...
}
使用bindToLifecycle()
以Activity为例,在Activity中使用bindToLifecycle()方法,完成Observable发布的事件和当前的组件绑定,实现生命周期同步。从而实现当前组件生命周期结束时,自动取消对Observable订阅,代码如下:
public class MainActivity extends RxAppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 当执行onDestory()时, 自动解除订阅
Observable.interval(1, TimeUnit.SECONDS)
.doOnDispose(new Action() {
@Override
public void run() throws Exception {
Log.i(TAG, "Unsubscribing subscription from onCreate()");
}
})
.compose(this.bindToLifecycle())
.subscribe(new Consumer() {
@Override
public void accept(Long num) throws Exception {
Log.i(TAG, "Started in onCreate(), running until onDestory(): " + num);
}
});
}
}
下一篇文章将针对订阅流程以及线程管理的源码进行分析