为啥要学RxAndroid呢,因为我要用Retrofit,就这么简单粗暴;除了Rx还有OkHtpp3;接下来都会说的。不要着急~
给Android开发者的Rx详解建议看看这篇文章,看过之后会就会都明白了 。
一、基本概念和添加依赖
- Observer(观察者):事件触发的时候有什么样的行为;
- Observable(被观察者):决定什么时候触发事件,以及触发怎样的事件;
- subscribe(订阅):建立Observer和Observable之间的关联。
----》(被观察者要做什么之前告诉观察者我要做什么了,你做好准备,等被观察者行动时,观察者采取自己相应的动作,在这之前要有观察者和被观察者,还要建立它们之间的关系,要不怎么通话呀,怎么告诉要干啥了)
这里所说的事件主要有:
- 1、onNext:相当于onClick、onEvent;
- 2、onCompleted:事件队列完成;
- 3、onError:队列异常,队列终止,不会有事件发出
注意:onError和onComplete两者是互斥的,有且只能有一个,并且是事件序列的最后一个
在app的gradle.build中添加:compile ‘io.reactivex:rxandroid:1.0.1’
二、创建Observer、Observable、Subscribe
- 1、使用Observer类创建Observer
/**
* 观察者的作用:事件触发的时候将有怎样的行为
*/
private void createObserver() {
Observer<String> stringObserver = new Observer<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
}
};
}
- 2、使用Subscriber类创建Observer
//创建Observer的扩展类,Subscriber是实现了Observer的抽象类
private void expanObserver() {
Subscriber<String> stringSubscriber = new Subscriber<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
}
@Override
public void onStart() {
super.onStart();
}
};
}
- 3、Observer和Subscriber关系
关联:
实质上,在 RxJava 的 subscribe 过程中,Observer 也总是会先被转换成一个 Subscriber
再使用。所以如果你只想使用基本功能,选择 Observer 和 Subscriber 是完全一样的。区别:
1)、onStart():这是 Subscriber增加的方法。它会在subscribe刚开始,而事件还未发送之前被调用,可以用于做一些准备工作,例如数据的清零或重置。这是一个可选方法,默认情况下它的实现为空。需要注意的是,如果对准备工作的线程有要求(例如弹出一个显示进度的对话框,这必须在主线程执行),
onStart()就不适用了,因为它总是在 subscribe所发生的线程被调用,而不能指定线程。要在指定的线程来做准备工作,可以使用
doOnSubscribe()方法,具体可以在后面的文中看到。
2)、unsubscribe(): 这是Subscriber所实现的另一个接口 Subscription的方法,用于取消订阅。 在这个方法被调用后,Subscriber将不再接收事件。一般在这个方法调用前,可以使用 isUnsubscribed()先判断一下状态。 unsubscribe()这个方法很重要,因为在 subscribe() 之后, Observable会持有Subscriber的引用,这个引用如果不能及时被释放,将有内存泄露的风险。 所以最好保持一个原则:要在不再使用的时候尽快在合适的地方(例如
onPause() onStop()等方法中)调用 unsubscribe()来解除引用关系,以避免内存泄露的发生。
- 4、创建被观察者Observable
/**
* 被观察者的作用:决定什么时候触发事件,以及触发怎样的事件
*/
private void createObservable() {
//create是创建事件序列的方法
Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
//当被观察者observable被订阅的时候,该方法会自动被调用(及observable.subscribe(observer);时才真正调用)
@Override
public void call(Subscriber<? super String> subscriber) {
//观察者subscriber将会调用两次onNext()和一次onCompleted(),----》这样被观察者调用了观察者的回调方法,就实现类由被观察者向观察者的事件传递,即观察者模式
subscriber.onNext("hello");
subscriber.onNext("world");
subscriber.onCompleted();
}
});
}
- 5、创建被观察者带参数情况
private void createOtherEventSequeue() {
//just将传入的参数依次发送出来
Observable observable_just = Observable.just("hello", "world");
//将传入的 数组 或 Iterable 拆分成具体对象后,依次发送出来。
String[] words = {"hello", "world"};
Observable observable_from = Observable.from(words);
// 以上两者都相当于下面的逻辑:
// onNext("hello");
// onNext("world");
// onCompleted();
}
- 6、创建Subscribe
private void subscribe(){
//创建观察者
Observer<String> observer = new Observer<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
Log.e("----------->","s"+s);
}
};
//创建被观察者
Observable<String> observable = Observable.just("hello","world");
//建立关联
observable.subscribe(observer);
}
三、线程控制Scheduler
- 1、说明:
在不指定线程的情况下, RxJava遵循的是线程不变的原则,即:在哪个线程调用 subscribe(),就在哪个线程生产事件;
在哪个线程生产事件,就在哪个线程消费事件。如果需要切换线程,就需要用到 Scheduler(调度器)。
Scheduler ——调度器,相当于线程控制器,RxJava通过它来指定每一段代码应该运行在什么样的线程。
- 2、RxJava提供的几种Scheduler
1)Schedulers.immediate():直接在当前线程运行,相当于不指定线程。这是默认的 Scheduler。
2)Schedulers.newThread(): 总是启用新线程,并在新线程执行操作。
3)Schedulers.io():I/O操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread()差不多,区别在于 io()的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io()比 newThread() 更有效率。不要把计算工作放在 io()中,可以避免创建不必要的线程。
4)Schedulers.computation():计算所使用的 Scheduler。这个计算指的是 CPU密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler使用的固定的线程池,大小为 CPU核数。不要把 I/O操作放在 computation()中,否则 I/O操作的等待时间会浪费 CPU。
5)AndroidSchedulers.mainThread():它指定的操作将在 Android主线程运行。
- 3、有了这几个 Scheduler ,就可以使用 subscribeOn() 和 observeOn() 两个方法来对线程进行控制了。
subscribeOn():指定 subscribe()所发生的线程,即 Observable.OnSubscribe被激活时所处的线程。或者叫做事件产生的线程。
observeOn():指定 Subscriber所运行在的线程。或者叫做事件消费的线程。
注意:通过 observeOn()的多次调用,程序实现了线程的多次切换。不过,不同于 observeOn(), subscribeOn()的位置放在哪里都可以,但它是只能调用一次的。
- 4、看看怎么使用的吧
private void scheduler() {
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
Log.e("------------>","call"+",thread"+Thread.currentThread().getName());
subscriber.onNext("我就看看好用不,看看怎么用");
subscriber.onCompleted();
}
})
.subscribeOn(Schedulers.io())// 指定 subscribe() 发生在 IO 线程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
.subscribe(new Observer<String>() {
@Override
public void onCompleted() {
Log.e("------------>","onCompleted"+",thread"+Thread.currentThread().getName());
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
Log.e("------------>","s"+s+",thread"+Thread.currentThread().getName());
}
});
}
private void moreScheduler(){
//通过 observeOn()的多次调用,程序实现了线程的多次切换。不过,不同于observeOn(),subscribeOn()的位置放在哪里都可以,但它是只能调用一次的。
Observable.just(1, 2, 3, 4) // IO 线程,由 subscribeOn() 指定
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.newThread())
.map(new Func1<Integer, String>() {
@Override
public String call(Integer s) {
return null;
}
}) // 新线程,由 observeOn() 指定
.observeOn(Schedulers.io())
.map(new Func1<String, String>() {
@Override
public String call(String s) {
return null;
}
}) // IO 线程,由 observeOn() 指定
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
}
}); // Android 主线程,由 observeOn() 指定
}
- 5、doOnSubscribe()
/**
* 在前面讲 Subscriber 的时候,提到过 Subscriber 的 onStart() 可以用作流程开始前的初始化。
* 然而 onStart() 由于在 subscribe() 发生时就被调用了,因此不能指定线程,而是只能执行在 subscribe() 被调用时的线程。
* 这就导致如果 onStart() 中含有对线程有要求的代码(例如在界面上显示一个 ProgressBar,这必须在主线程执行),将会有线程非法的风险,因为有时你无法预测 subscribe() 将会在什么线程执行。
* 而与 Subscriber.onStart() 相对应的,有一个方法 Observable.doOnSubscribe() 。
* 它和 Subscriber.onStart() 同样是在 subscribe() 调用后而且在事件发送前执行,但区别在于它可以指定线程。
* 默认情况下, doOnSubscribe() 执行在 subscribe() 发生的线程;而如果在 doOnSubscribe() 之后有 subscribeOn() 的话,它将执行在离它最近的 subscribeOn() 所指定的线程。
*/
private void doOnSubscribe(){
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
}
})
.subscribeOn(Schedulers.io())
.doOnSubscribe(new Action0() {
@Override
public void call() {
//TODO 转菊花
// 需要在主线程执行
}
})
.subscribeOn(AndroidSchedulers.mainThread()) // 指定主线程(指定doOnSubscribe中逻辑在哪个线程执行)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
}
});
}
四、Map、FlatMap、Compose转换的使用
所谓变换,就是将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列。
说白了就是针对事件序列的处理和再发送
原理:通过事件拦截和处理实现事件序列的变换。
- 1、Map的使用
/**
* map:一对一的转化
*
* map() 方法将参数中的 String 对象转换成一个 Bitmap 对象后返回,而在经过 map() 方法后,
* 事件的参数类型也由 String 转为了 Bitmap。(String和Bitmap只是举例子,实际中可以自己决定)
*/
private void transformMap() {
//Func类包装的是又返回值的方法
Observable.just("http://q.qlogo.cn/qqapp/1105900198/8648E396207223FD4B9982F7E772D3A9/100")
.map(new Func1<String, Bitmap>() {// 输入类型 String
@Override
public Bitmap call(String path) {// 参数类型 String
try {
URL url = new URL(path);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
if (connection.getResponseCode() == 200) {
return BitmapFactory.decodeStream(connection.getInputStream());// 返回类型 Bitmap
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}).subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Bitmap>() {
@Override
public void call(Bitmap bitmap) {// 参数类型 Bitmap
mImageView.setImageBitmap(bitmap);
}
});
}
- 2、FlatMap的使用
/**
* flatMap() 和 map() 有一个相同点:它也是把传入的参数转化之后返回另一个对象。
* 但需要注意,和 map() 不同的是, flatMap() 中返回的是个 Observable 对象,
* 并且这个 Observable 对象并不是被直接发送到了 Subscriber 的回调方法中。
*
* flatMap() 的原理是这样的:
* 1. 使用传入的事件对象创建一个 Observable 对象;
* 2. 并不发送这个 Observable, 而是将它激活,于是它开始发送事件;
* 3. 每一个创建出来的 Observable 发送的事件,都被汇入同一个 Observable ,而这个 Observable 负责将这些事件统一交给 Subscriber 的回调方法。
*/
private void transformFlatMap() {
List<Student> students = new ArrayList<>();
for (int j = 0; j < 3; j++) {
Student student = new Student();
student.setName("王五");
List<Course> courses = new ArrayList<>();
for (int i = 0; i < 3; i++) {
Course course = new Course();
course.setCourseName("课程" + i);
courses.add(course);
}
student.setCourses(courses);
students.add(student);
}
Observable.from(students).flatMap(new Func1<Student, Observable<Course>>() {
@Override
public Observable<Course> call(Student student) {
return Observable.from(student.getCourses());
}
}).subscribe(new Action1<Course>() {
@Override
public void call(Course course) {
Log.e("---------->", "course_name:" + course.getCourseName());
}
});
}
//学生类
class Student {
private String name;
private List<Course> courses;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
}
//课程类
class Course {
private String courseName;
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
}
注意:call方法执行了9次,因为有3个学生,每个学生有3门课,所以是9次,不是一次哦。
- 3、Compose的使用
/**
* compose和Transformer,自定义Transformer实现Observable.Transformer接口,
* 就相当于一个方法,将功能封装好,每次调用方法就可以,这里只不过是把方法封在了compose中。
*
* 举例子:加入你要一个大萝卜,然后生产大萝卜的过程被封装在Transformer中,相当于一个人,然后每次你要萝卜的时候就用compose的方法,然后找到Transformer这个人就可以得到大萝卜了。
*
* Transformer实质上就是一个Func1<Observable<T>, Observable<R>>,就是将一个类型转换为另一个类型
*/
public void transformCompose() {
Observable.just("111", "2222")
.compose(new DefaultTransformer<String>())
.subscribe(new Subscriber<List<String>>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(List<String> strings) {
Log.e("------------->", "strings" + strings.size());
for (int i = 0; i < strings.size(); i++) {
Log.e("------------>", "element:" + strings.get(i));
}
}
});
}
public class DefaultTransformer<T> implements Observable.Transformer<T,List<T>> {
@Override
public Observable<List<T>> call(Observable<T> tObservable) {
return tObservable.subscribeOn(Schedulers.io()).map(new Func1<T, List<T>>() {
@Override
public List<T> call(T t) {
List<T> list = new ArrayList<T>();
list.add(t);
return list;
}
});
}
}
我这里把字符串转为字符串列表了,感觉没多大用哈,就是举例子嘿嘿。