虽然已经有了Rxjava2与RxAndroid2,但还是先来理解下Rxjava1的思路。
首先老规矩,加入包引用
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.1.6'
RxJava1的概念和思路,比较推荐大家去看 扔物线 大神的文章,附带文章链接,本文也参考大神的文章进行说明哦。
http://gank.io/post/560e15be2dca930e00da1083
RxJava1 有四个基本概念:Observable (可观察者,即被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer,Android 开发中一个比较典型的例子是点击监听器 OnClickListener 。对设置 OnClickListener 来说, View 是被观察者, OnClickListener 是观察者,二者通过 setOnClickListener() 方法达成订阅关系。订阅之后用户点击按钮的瞬间,Android Framework 就会将点击事件发送给已经注册的 OnClickListener 。采取这样被动的观察方式,既省去了反复检索状态的资源消耗,也能够得到最高的反馈速度。
1、基本实现
Observer observer = new Observer() {
@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!");
}
};
Subscriber subscriber = new Subscriber() {
@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!");
}
};
Observable observable = Observable.create(new Observable.OnSubscribe() {//创建 Observable
@Override
public void call(Subscriber super String> subscriber) {
subscriber.onNext("Hello");
subscriber.onNext("Hi");
subscriber.onNext("Aloha");
subscriber.onCompleted();
}
});
// Observable observable = Observable.just("Hello", "Hi", "Aloha");
// String[] words = {"Hello", "Hi", "Aloha"};
// Observable observable = Observable.from(words);
// observable.subscribe(observer);
observable.subscribe(subscriber);//Subscribe (订阅)
以上代码是较为简单的Rxjava1的使用,在订阅上有以上几种都是可以的,在创建观察者事件上Subscriber 对 Observer 接口进行了一些扩展,但他们的基本使用方式是完全一样的。只是Subscriber比Observer多了几种类型。
实质上,在 RxJava 的 subscribe 过程中,Observer 也总是会先被转换成一个 Subscriber 再使用。所以如果你只想使用基本功能,选择 Observer 和 Subscriber 是完全一样的。它们的区别对于使用者来说主要有两点:
onStart(): 这是 Subscriber 增加的方法。它会在 subscribe 刚开始,而事件还未发送之前被调用,可以用于做一些准备工作,例如数据的清零或重置。这是一个可选方法,默认情况下它的实现为空。需要注意的是,如果对准备工作的线程有要求(例如弹出一个显示进度的对话框,这必须在主线程执行), onStart() 就不适用了,因为它总是在 subscribe 所发生的线程被调用,而不能指定线程。要在指定的线程来做准备工作,可以使用 doOnSubscribe() 方法,具体可以在后面的文中看到。
unsubscribe(): 这是 Subscriber 所实现的另一个接口 Subscription 的方法,用于取消订阅。在这个方法被调用后,Subscriber 将不再接收事件。一般在这个方法调用前,可以使用 isUnsubscribed() 先判断一下状态。 unsubscribe() 这个方法很重要,因为在 subscribe() 之后, Observable 会持有 Subscriber 的引用,这个引用如果不能及时被释放,将有内存泄露的风险。所以最好保持一个原则:要在不再使用的时候尽快在合适的地方(例如 onPause() onStop() 等方法中)调用 unsubscribe() 来解除引用关系,以避免内存泄露的发生。
-----摘录自 扔物线大神文章
在Observable中还有以下这种写法Action0~ActionX的写法。
Observable observable = null;
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 = Observable.just("Hello", "Hi", "Aloha");
// 自动创建 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);
场景示例,将字符串数组 names 中的所有字符串依次打印出来。
String[] names={"rxjava1","rxandroid1","rxjava2","rxandroid2"};
Observable.from(names)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1() {
@Override
public void call(String s) {
Log.d(tag,s);
}
});
由 id 取得图片并显示
final int drawableRes=R.drawable.spider;
final ImageView imageview=(ImageView) findViewById(R.id.image1);
Observable.create(new Observable.OnSubscribe() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void call(Subscriber super Drawable> subscriber) {
Drawable drawable = getTheme().getDrawable(drawableRes);
subscriber.onNext(drawable);
subscriber.onCompleted();
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@Override
public void onNext(Drawable drawable) {
imageview.setImageDrawable(drawable);
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
Toast.makeText(MainActivity.this, "Error!", Toast.LENGTH_SHORT).show();
}
});
以上两个示例使用了线程控制 —— Scheduler,subscribeOn控制的是在它之前的代码,而observeOn控制的是在它之后的代码的线程。
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 主线程运行。
Student[] students = {student,student2};
Subscriber subscriber = new Subscriber() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String name) {
Log.d(tag, name);
}
};
Observable.from(students)
.map(new Func1() {
@Override
public String call(Student student) {
return student.getName();
}
})
.subscribe(subscriber);
这里出现了一个叫做 Func1 的类。它和 Action1 非常相似,也是 RxJava 的一个接口,用于包装含有一个参数的方法。 Func1 和 Action 的区别在于, Func1 包装的是有返回值的方法。另外,和 ActionX 一样, FuncX 也有多个,用于不同参数个数的方法。FuncX 和 ActionX 的区别在 FuncX 包装的是有返回值的方法。
如果我们再假设:如果要打印出每个学生所需要修的所有课程的名称呢?(需求的区别在于,每个学生只有一个名字,但却有多个课程。)首先可以这样实现:
Student[] students = {student,student2};
Subscriber subscriber = new Subscriber() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Student student) {
List courses = student.getCoures();
for (int i = 0; i < courses.size(); i++) {
Course course = courses.get(i);
Log.d(tag, course.getCourseName());
}
}
};
Observable.from(students)
.subscribe(subscriber);
如果不想使用for循环,那我们就使用flatMap() :
Student[] students = {student,student2};
Subscriber subscriber = new Subscriber() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Course course) {
Log.d(tag, course.getCourseName());
}
};
Observable.from(students)
.flatMap(new Func1>() {
@Override
public Observable call(Student student) {
return Observable.from(student.getCoures());
}
})
.subscribe(subscriber);
上面的代码可以看出, flatMap() 和 map() 有一个相同点:它也是把传入的参数转化之后返回另一个对象。但需要注意,和 map() 不同的是, flatMap() 中返回的是个 Observable 对象,并且这个 Observable 对象并不是被直接发送到了 Subscriber 的回调方法中。 flatMap() 的原理是这样的:1. 使用传入的事件对象创建一个 Observable 对象;2. 并不发送这个 Observable, 而是将它激活,于是它开始发送事件;3. 每一个创建出来的 Observable 发送的事件,都被汇入同一个 Observable ,而这个 Observable 负责将这些事件统一交给 Subscriber 的回调方法。这三个步骤,把事件拆成了两级,通过一组新创建的 Observable 将初始的对象『铺平』之后通过统一路径分发了下去。而这个『铺平』就是 flatMap() 所谓的 flat。
Subscriber subscriber = new Subscriber() {
@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!");
}
};
Integer[] n = {1, 2, 3};
Observable.from(n).lift(new Observable.Operator() {
@Override
public Subscriber super Integer> call(final Subscriber super String> subscriber) {
// 将事件序列中的 Integer 对象转换为 String 对象
return new Subscriber() {
@Override
public void onNext(Integer integer) {
subscriber.onNext("" + integer);
}
@Override
public void onCompleted() {
subscriber.onCompleted();
}
@Override
public void onError(Throwable e) {
subscriber.onError(e);
}
};
}
}).subscribe(subscriber);
当含有 lift() 时:
1.lift() 创建了一个 Observable 后,加上之前的原始 Observable,已经有两个 Observable 了;
2.而同样地,新 Observable 里的新 OnSubscribe 加上之前的原始 Observable 中的原始 OnSubscribe,也就有了两个 OnSubscribe;
3.当用户调用经过 lift() 后的 Observable 的 subscribe() 的时候,使用的是 lift() 所返回的新的 Observable ,于是它所触发的 onSubscribe.call(subscriber),也是用的新 Observable 中的新 OnSubscribe,即在 lift() 中生成的那个 OnSubscribe;
4.而这个新 OnSubscribe 的 call() 方法中的 onSubscribe ,就是指的原始 Observable 中的原始 OnSubscribe ,在这个 call() 方法里,新 OnSubscribe 利用 operator.call(subscriber) 生成了一个新的 Subscriber(Operator 就是在这里,通过自己的 call() 方法将新 Subscriber 和原始 Subscriber 进行关联,并插入自己的『变换』代码以实现变换),然后利用这个新 Subscriber 向原始 Observable 进行订阅。
这样就实现了 lift() 过程,有点像一种代理机制,通过事件拦截和处理实现事件序列的变换。
当然了,Rxjava1还有衍生物RxBinding、RxBus等,Rxjava1在网络上常与Retrofit结合使用,因为Retrofit内包含有Observable,也更简洁。在此不做介绍,如需要请看扔物线大神的文章啦。
以上代码均在:
https://github.com/primerToforget/Rxjava1Test
附上:
RxBinding: https://github.com/JakeWharton/RxBinding
Retrofit与Rxjava1的demo:https://github.com/rengwuxian/RxJavaSamples/tree/1.x
欢迎大家学习交流。~