RxJava是什么
是一个异步库
RxJava好处是什么
让代码简洁,有序
RxJava的一些概念
- 重构的观察者
普通的观察者Observer
和Observable
,构成观察者-被观察者关系后,观察者回调方法只有一个。
而RxJava 的观察者增加了
- onNext 表示事件响应后,下一步操作
- onError 表示事件内部处理出错。
- onComplete 或者成功完成观察者的回调。
-
RxJava 的观察者包含 Observer 和 另一个替代 Observer 的 Subscriber 。
-
RxJava 有4个新增概念:观察者(Observer),被观察者(Observable),事件,订阅(subscribe)。
RxJava的基本用法
1. 首先要创建一个观察者 Observer:
Observer<String> observer = new Observer<String>() {
@Override
public void onNext(String s) {
Log.d(tag, "Item: " + s);
}
@Override
public void onCompleted() {
Log.d(tag, "Completed!");
}
@Override
public void onError(Throwable e) {
Log.d(tag, "Error!");
}
};
RxJava提供了一个可替换的 观察者 : Subscriber , 基本实现和Observer类似,也有些基本区别:
- onStart(): 这是 Subscriber 增加的方法。它会在 subscribe 刚开始,而事件还未发送之前被调用,可以用于做一些准备工作,例如数据的清零或重置。这是一个可选方法,默认情况下它的实现为空。需要注意的是,如果对准备工作的线程有要求(例如弹出一个显示进度的对话框,这必须在主线程执行), onStart() 就不适用了,因为它总是在 subscribe 所发生的线程被调用,而不能指定线程。要在指定的线程来做准备工作,可以使用 doOnSubscribe() 方法,具体可以在后面的文中看到。
- unsubscribe(): 这是 Subscriber 所实现的另一个接口 Subscription 的方法,用于取消订阅。在这个方法被调用后,Subscriber 将不再接收事件。一般在这个方法调用前,可以使用 isUnsubscribed() 先判断一下状态。 unsubscribe() 这个方法很重要,因为在 subscribe() 之后, Observable 会持有 Subscriber 的引用,这个引用如果不能及时被释放,将有内存泄露的风险。所以最好保持一个原则:要在不再使用的时候尽快在合适的地方(例如 onPause() onStop() 等方法中)调用 unsubscribe() 来解除引用关系,以避免内存泄露的发生。
2. 创建被观察者
Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello");
subscriber.onNext("Hi");
subscriber.onNext("Aloha");
subscriber.onCompleted();
}
});
看到上面的Observable.OnSubscribe接口没,就是他最终调用了 subscriber 的事件发送方法onNext(), onCompleted()等。
3. 使用subscribe方法让二者建立订阅关系
observable.subscribe(observer);
以上,就建立了观察者和被观察者之间的订阅关系。
其实现代码,也给一下, 后面会用到:
// 注意:这不是 subscribe() 的源码,而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。
// 如果需要看源码,可以去 RxJava 的 GitHub 仓库下载。
public Subscription subscribe(Subscriber subscriber) {
subscriber.onStart();
onSubscribe.call(subscriber);
return subscriber;
}
除了上面的那种 Observer, 还可以给subcribe()方法传入不完整的接口:
Action1<String> onNextAction = new Action1<String>() {
// onNext()
@Override
public void call(String s) {
Log.d(tag, s);
}
};
Action1<Throwable> onErrorAction = new Action1<Throwable>() {
// onError()
@Override
public void call(Throwable throwable) {
// Error handling
}
};
Action0 onCompletedAction = new Action0() {
// onCompleted()
@Override
public void call() {
Log.d(tag, "completed");
}
};
// 自动创建 Subscriber ,并使用 onNextAction 来定义 onNext()
observable.subscribe(onNextAction);
// 自动创建 Subscriber ,并使用 onNextAction 和 onErrorAction 来定义 onNext() 和 onError()
observable.subscribe(onNextAction, onErrorAction);
// 自动创建 Subscriber ,并使用 onNextAction、 onErrorAction 和 onCompletedAction 来定义 onNext()、 onError() 和 onCompleted()
observable.subscribe(onNextAction, onErrorAction, onCompletedAction);
上面的Action0, Action1, Action2 ,就是RxJava提供的自定义类型接口。都可以匿名内部类对象的形式,传给observable.subscribe()
. Action0
提供一个 call()
无参无返回值的方法, Action1 的call方法会多一个参数,他们都是对 onComplete()方法的包装,而已,最终,会回调到 call()方法。(ps:RxJava2 好像去掉这个Action0了)
4. 创建事件序列
有了观察者,被观察者之间的订阅关系,还需要产生事件,在观察者和被观察者之间流动对吧,所以RxJava提供了
- create(“Hello”, “Hi”, “Aloha”)
- just(…)
- from(“Hello”, “Hi”, “Aloha”"")
等方法,去创造事件序列
Scheduler
一般使用RxJava时,我们这样用:
int drawableRes = ...;
ImageView imageView = ...;
Observable.create(new OnSubscribe<Drawable>() {
@Override
public void call(Subscriber<? super Drawable> subscriber) {
Drawable drawable = getTheme().getDrawable(drawableRes));
// 产生事件的位置
subscriber.onNext(drawable);
subscriber.onCompleted();
}
})
.subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
.subscribe(new Observer<Drawable>() {
@Override
public void onNext(Drawable drawable) {
// 消耗事件的位置
imageView.setImageDrawable(drawable);
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
Toast.makeText(activity, "Error!", Toast.LENGTH_SHORT).show();
}
});
上面,通过调用 subscribeOn(Schedulers.io())
, .observeOn(AndroidSchedulers.mainThread())
, 我们可以指定执行产生事件的线程Schedulers.io(), 消耗事件回调方法所在的线程AndroidSchedulers.mainThread(),那RxJava是如何做到的呢?
首先,我们要理解它的一个方法(或者叫概念,又是概念)
变换事件
RxJava内部,通过一个稍显复杂的操作,可以“将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列“,
事件序列是啥?先来一段代码:
Observable.just("images/logo.png") // 输入类型 String
.map(new Func1<String, Bitmap>() {
@Override
public Bitmap call(String filePath) { // 参数类型 String
// 位置1
return getBitmapFromPath(filePath); // 返回类型 Bitmap
}
})
.subscribe(new Action1<Bitmap>() {
@Override
public void call(Bitmap bitmap) { // 参数类型 Bitmap
// 位置2
showBitmap(bitmap);
}
});
上面的 new Func1(), 还有 new Aciton1() 匿名类对象,都是 事件,他们会有一些事件方法,方法的参数,看着不同啊,那,代码为何可以从一个方法跳到另一个方法**(位置1 -》 位置2)**执行呢?
原因就是有 map() 这个方法。他可以将一个事件或者事件序列变换成另一个事件或者事件序列。
具体的原理呢,后续会讲到(也可能讲不到)。~~!
总之,这个map()方法非常重要,也非常牛逼,先记住:map()做到了事件或者事件序列的转换。
当然, 还有其他方法,map方法更牛逼:
- flatMap() 非常6的一个方法,解释起来都困难(暂时不解释了),
和map的区别是:变换后返回值是一个Observable对象。
- throttleFirst() 每次事件触发后的一定时间间隔内丢弃新的事件。常用作去抖动过滤,例如按钮的点击监听器:
变换的原理
这一段最绕了。不过还是可以看一看。
- 变换虽然功能各有不同,但实质上都是针对事件序列的处理和再发送。而在 RxJava 的内部,它们是基于同一个基础的变换方法: lift(Operator)。
代码1
// 注意:这不是 lift() 的源码,而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。
// 如果需要看源码,可以去 RxJava 的 GitHub 仓库下载。
public <R> Observable<R> lift(Operator<? extends R, ? super T> operator) {
return Observable.create(new OnSubscribe<R>() {
@Override
public void call(Subscriber subscriber) {
Subscriber newSubscriber = operator.call(subscriber);
newSubscriber.onStart();
onSubscribe.call(newSubscriber);
}
});
}
上面一段代码发生了神马?为什么就可以执行变换事件或者事件序列的牛皮操作呢?
这里,我把之前 subscribe()方法也拷过来,对比一下:
代码2
// 注意:这不是 subscribe() 的源码,而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。
// 如果需要看源码,可以去 RxJava 的 GitHub 仓库下载。
public Subscription subscribe(Subscriber subscriber) {
subscriber.onStart();
onSubscribe.call(subscriber);
return subscriber;
}
这里,代码1那段call()
方法几乎和代码2的 subscribe()
方法类似 ,新生成了一个 newSubscriber
(前面说过,等价于 Observer
), 然后调用 onStart()
方法,把 newSubscriber
关联到旧的 onSubscribe 对象中。
- subscribe() 中这句话的 onSubscribe 指的是 Observable 中的 onSubscribe 对象,是否还记得create 方法?
- 当含有 lift() 时:
-
lift() 创建了一个 Observable 后,加上之前的原始 Observable,已经有两个 Observable 了;
-
而同样地,新 Observable 里的新 OnSubscribe 加上之前的原始 Observable 中的原始 OnSubscribe,也就有了两个 OnSubscribe;
-
当用户调用经过 lift() 后的 Observable 的 subscribe() 的时候,使用的是 lift() 所返回的新的 Observable ,于是它所触发的 onSubscribe.call(subscriber),也是用的新 Observable 中的新 OnSubscribe,即在 lift() 中生成的那个 OnSubscribe;
-
而这个新 OnSubscribe 的 call() 方法中的 onSubscribe ,就是指的原始 Observable 中的原始 OnSubscribe ,在这个 call()方法里,新 OnSubscribe 利用
operator.call(subscriber)
生成了一个新的Subscriber
(Operator 就是在这里,通过自己的call()
方法将新 Subscriber 和原始 Subscriber 进行关联,并插入自己的『变换』代码以实现变换),然后利用这个新 Subscriber 向原始 Observable 进行订阅。
这样就实现了 lift() 过程,有点像一种代理机制,通过事件拦截和处理实现事件序列的变换。
-
第4点太绕了。
用自己的话描述,就是: Observable 执行了lift操作,形成一个新的Observable对象,代理了旧的Observable,有事件过来,先通过新的,转发给旧的,旧的再通知代理的 Subscriber
. 最后再分发给 目标 Subscriber
。
还是打个比方吧:
有个卖房子的中介毛利小O
, 现在有个人Subscriber
要找他买房子,但是他没有房源;
于是,他只能找售楼部的中介 工藤新O
, 中介 毛利小O
的买房人就成为工藤新O
的 Subscriber
。but!中介 工藤新O
很聪明,他要搞个操作对毛利小O
的买房人(旧的Subscriber)进行一层关联和变换。即:operator.call(subscriber)
。生成一个新的Subscriber, 并且里面有自己的一些操作。然后调用onSubscribe.call(newSubscriber) 把新的和旧的进行一个关联。
接着,中介 工藤新O
就能利用新的Subscriber,实现自己的目的了(对房价实现一些不可告人的操作)了。
线程控制的原理
to be continue