简介
RxJava 在 GitHub的自我介绍是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。同时也是基于观察者模式的一个库。
要使用他首先要添加依赖
compile 'io.reactivex:rxjava:1.0.14'
compile 'io.reactivex:rxandroid:1.0.1'
类介绍
- Observable 被观察者
- Observer 观察者
- subscribe() 他们链接的桥梁
- Subscriber,他是Observer的实现类,并将方法进行拓展。
这个关系用代码来表示如图所示:
//观察者
Observer observer = new Observer() {
@Override
public void onCompleted() {
Log.e("onCompleted: ", "完成");
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
Log.e("onNext: ", s);
}
};`
//被观察者
Observable observable = Observable.create(new Observable.OnSubscribe() {
@Override
public void call(Subscriber super String> subscriber) {
Log.e("call: ", Thread.currentThread().getName());
subscriber.onNext("我");
subscriber.onNext("爱");
subscriber.onNext("你");
subscriber.onCompleted();
}
});
然后桥梁将让他们之间产生链接:
observable.subscribe(observer);
这样一个简单的Rxjava模型就写好了,可以看一下输出结果:
com.example.cosima.rxjavalearn E/onNext:: 我
com.example.cosima.rxjavalearn E/onNext:: 爱
com.example.cosima.rxjavalearn E/onNext:: 你
com.example.cosima.rxjavalearn E/onCompleted:: 完成
我们也可以将上面的Observer用Subscriber来代替,如下:
Subscriber subscriber = new Subscriber() {
@Override
public void onStart() {
Log.e("onStart: ", "开始");
Log.e("onStart: ", Thread.currentThread().getName());
}
@Override
public void onCompleted() {
Log.e("onCompleted: ", "完成");
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
Log.e("onNext: ", s);
}
};
Subscriber中比Observer多了一个Onstart方法,它会在 subscribe 刚开始,而事件还未发送之前被调用,可以用于做一些准备工作,例如数据的清零或重置。这是一个可选方法,默认情况下它的实现为空。
Observable的创建
上面介绍了一种创建方式是使用create()方法创建的,该方法是最基本的创造事件队列的方法,基于这个方法外,RxJava还提供了一些方法来快捷穿件事件队列
- just(T..); 将需要的参数依次传入。
- from(T[]); 将需要的参数添加到数组中传入。
将观察者与被观察者联系起来除了subscribe(Observer) 和 subscribe(Subscriber) ,subscribe() 还支持不完整定义的回调。如下所示:
Action1 onNextAction = new Action1() {
// onNext()
@Override
public void call(String s) {
Log.d(tag, s);
}
};
Action1 onErrorAction = new Action1() {
// onError()
@Override
public void call(Throwable throwable) {
// Error handling
}
};
Action0 onCompletedAction = new Action0() {
// onCompleted()
@Override
public void call() {
Log.d(tag, "completed");
}
};
observable.subscribe(onNextAction);
observable.subscribe(onNextAction, onErrorAction);
observable.subscribe(onNextAction, onErrorAction, onCompletedAction);
上述代码提到了Action0和Action1,他们都是RxJava的接口,同样都只有一个方法Call(),不同的是,Action0的Call()方法中是没有参数也没有返回值的,对应了OnCompleted()这个方法;Action1的Call( T param)方法中含有参数,分别对应了OnNext(T param)和OnError(Throwable error)两个方法。具体使用如下:
String[] loves = {"I", "will", "always", "love", "you"};
Observable.from(loves).subscribe(new Action1() {
@Override
public void call(String s) {
Log.e("call: ", s);
}
});
最开始的时候就讲了RxJava是可以进行异步操作的,但是上面讲的都是进行的同步操作,下面就讲RxJava的另一个概念Scheduler
线程控制Scheduler
在不指定线程的情况下,RxJava遵循线程不变的原则,在哪个线程调用subscribe(),事件就在哪个线程发生,也在这个线程消费,当我们需要切换线程的时候就需要用到Scheduler。
- Schedulers.immediate(): 直接在当前线程运行,相当于不指定线程。这是默认的 Scheduler。
- Schedulers.newThread(): 总是启用新线程,并在新线程执行操作。
- Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。
- Schedulers.computation(): 计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
- 另外, Android 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操作将在 Android 主线程运行。
然后我们可以使用subscribeOn() 和 observeOn() 两个方法来对线程进行控制。
subscribeOn(): 指定 subscribe() 所发生的线程。事件产生的线程。
-
observeOn(): 指定 Subscriber 所运行在的线程。事件消费的线程。
然后我们通过代码理解一下这个SchedulerObservable.create(new Observable.OnSubscribe
() { @Override public void call(Subscriber super String> subscriber) { subscriber.onNext("我"); subscriber.onNext("爱"); subscriber.onNext("你"); subscriber.onCompleted(); } }) .subscribeOn(Schedulers.io()) .doOnSubscribe(new Action0() { @Override public void call() { Log.e("call: ", Thread.currentThread().getName()); mProgressBar.setVisibility(View.VISIBLE); } }) .observeOn(AndroidSchedulers.mainThread()) .subscribe(subscriber);
subscribeOn(Schedulers.io()) 指定创建的时间在IO线程中发出,observeOn(AndroidScheculers.mainThread()) 指定事件消费在主线程中消费,这种方式非常常见,适用于子线程取数据,然后主线程显示。同时,可以看到我在上述代码中新添加了一个方法doOnSubscribe(),该方法与Subscriber的OnStart()方法相似,在事件产生前在OnStart()之后就会执行,但是在该方法之前的subscribeOn()不会影响他,只有在他之后且离他最近的一个subscribeOn() 才会影响。
- observeOn()可以执行多次,他所影响的是指定之后的操作所在的线程。
- subscribeOn()也可以执行多次,从事件开端就造成影响,有多个的时候只有第一个 subscribeOn() 起作用。
接下来可以说是RxJava最牛逼的地方了。
变换
1. map();
2. flatMap();
让我们首先来看map()
Observable.from(number)
.map(new Func1() {
@Override
public Integer call(String s) {
Integer integer = Integer.valueOf(s);
Log.e("call--1--: ", integer + "");
return integer;
}
})
.subscribe(new Action1() {
@Override
public void call(Integer integer) {
Log.e("call--2--: ", integer + "");
}
});
在这里又新出现了一个类Func1,他与Action1非常相似,也是RxJava的一个接口,但是与Action1不同的是Func1是有返回值的。可以看到的是在map()中将String类型的参数转换为Integer类型后返回 。
接下来让我们看flatMap(), 这边举个例子,我们要打印学生的课程信息,学生的课程不一定是只有一个的,可能有很多个,所以要这个时候就要用到flatMap();
Student[] students = ...;
Subscriber subscriber = new Subscriber() {
@Override
public void onNext(Course course) {
Log.d(tag, course.getName());
}
};
Observable.from(students)
.flatMap(new Func1>() {
@Override
public Observable call(Student student) {
return Observable.from(student.getCourses());
}
})
.subscribe(subscriber);
从上面的代码可以看出,flatMap和Map的相同点就是把一个对象转化为另一个对象返回,但是不同的是flatMap()返回的是个Observable对象,并且这个对象并不是直接发送到了回调方法中,而是把这个对象激活,之后将他发送到回调方法中。
变换的原理
这些变换虽然功能各有不同,但实质上都是针对事件序列的处理和再发送。而在 RxJava 的内部,它们是基于同一个基础的变换方法: lift(Operator)。
注意:这不是 lift() 的源码,而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。
如果需要看源码,可以去 RxJava 的 GitHub 仓库下载。
public Observable lift(Operator extends R, ? super T> operator) {
return Observable.create(new OnSubscribe() {
@Override
public void call(Subscriber subscriber) {
Subscriber newSubscriber = operator.call(subscriber);
newSubscriber.onStart();
onSubscribe.call(newSubscriber);
}
});
}
在这里我就说一下我所理解的lift()的原理吧:
说简单点就是,你自己定义的Observable1含有lift()时,会生成一个Observable,我们叫他Observable2,Observable2中会有一个OnSubscribe(),然后调用lift()时,新生成的 OnSubscribe 利用 operator.call(subscriber) 生成了一个新的 Subscriber( call() 方法将新 Subscriber 和原始 Subscriber 进行关联)然后通过新生成的Subscriber与Observable1进行订阅有点像一种代理机制,通过事件拦截和处理实现事件序列的变换。
compose: 对 Observable 整体的变换
这个地方就像是对Observable进行封装,实现Observable.Transformer接口并重写Call()就可以了,在这里就不多说了。
RxJava的使用场景和使用方式#
与Retrofit结合使用
直接上代码吧,
1. 首先初始化Retrofit
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://japi.juhe.cn/joke/content/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())//基于RxJava1.0
.build();
2. 定义返回Observable的请求
@GET("text.from?page=1&pagesize=20&key=f1bdc177567c6fbe53d918041004c0b1")
Observable getJokeContent();
3. 开始请求并返回数据
JokeService service = retrofit.create(JokeService.class);
service.getJokeContent()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1() {
@Override
public void call(JokeBean jokeBean) {
String content = jokeBean.getResult().getData().get(0).getContent();
mTextView.setText(content);
}
});
如果需要耗时操作就doOnNext()方法中进行操作,如果需要连续访问的话就使用flatMap(),如下所示
@GET("/token")
public Observable getToken();
@GET("/user")
public Observable getUser(@Query("token") String token, @Query("userId") String userId);
...
getToken()
.flatMap(new Func1>() {
@Override
public Observable onNext(String token) {
return getUser(token, userId);
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@Override
public void onNext(User user) {
userView.setUser(user);
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable error) {
// Error handling
...
}
});
参考:给Android开发者的RxJava详解
不对之处欢迎指正!推荐一个Android实习&&经验交流群:541144061