RxJava学习笔记(一)
来源:互联网 发布:2017淘宝违规考试答案 编辑:程序博客网 时间:2024/06/11 22:39
该笔记通过“RxJava 详解”学习记录
学习RxJava之前需要了解“观察者模式”
RxJava四个基本概念
1、Observable — 被观察者
2、Observer — 观察者
3、Subscribe — 订阅
4、事件
RxJava有两种事件:
1、普通事件 onNext()
2、特殊事件 onCompleted() — 时间队列完结。当不会再有新的onNext()发出时,需出发onCompleted()方法作为标志。
onError() — 事件队列异常。当事件处理过程中出现异常时,onError会被触发,同时队列自动终止。
注:一个正确的事件队列中,onCompleted()和onError()有且只有一个,并且是事件序列中的最后一个。onCompleted()与onError()二者互斥,即在队列中调用了其中一个,就不应该在调用另一个。
创建Observer,即观察者
它决定事件触发时将有怎样的行为。
Observer<String> observer = new Observer<String>(){ @Override public void onNext(String s){ Log.d(tag,s); } @Override public void onCompleted(){ Log.d(tag,"Completed!"); } @Override public void onError(Throwable e){ Log.d(tag,s); }}
或可以
创建Subscriber,即订阅者
它是Observer的抽象类,对Observer接口进行了拓展。
Subscriber<String> subscriber = new Subscriber<String>(){ @Override public void onNext(String s){ Log.d(tag,s); } @Override public void onCompleted(){ Log.d(tag,"Completed!"); } @Override public void onError(Throwable e){ Log.d(tag,s); }}
Observer与Subscriber之间的区别:
1.onStart():这是Subscriber增加的方法。它会在subscribe(订阅)刚开始,而事件还未发送之前被调用,可以用于做一些准备工作,例如数据的清零或重置。这是一个可选方法,默认情况下它的实现为空。需要注意的是,如果对准备工作的线程有要求(例如弹出一 个显示进度的对话框,这必须在主线程执行),onStart()就不适用了,因为它总是在subscribe(订阅)所发生的线程被调用,而不能指定线程。要在指定的线程来做准备工作,可以使用 doOnSubscribe() 方法。
2.unsubscribe():这是Subscriber所实现的另一个接口Subscription的方法,用于取消订阅。在这个方法被调用后,Subscriber将不再接收事件。一般在这个方法调用前,可以使用isUnsubscribed()先判断一下状态。unsubscribe()这个方法很重要,因为在subscribe()之后,Observable会持有Subscriber的引用,这个引用如果不能及时被释放,将有内存泄露的风险。所以最好保持一个原则:要在不再使用的时候尽快在合适的地方(例如onPause() onStop() 等方法中)调用 unsubscribe() 来解除引用关系,以避免内存泄露的发生。
创建Observable,即被观察者
它决定什么时候触发时间以及吃法怎样的时间。
1.使用create()方法创建
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(); }});
对create()方法的详解:这里传入一个OnSubscribe对象作为参数。OnSubscribe会被存储在返回的Observale对象中,他的作用相当于一个计划表,当Observable被订阅时,OnSubscribe的call()方法会自动被调用,事件序列就会依照设定依次触发。
2.使用just(T…)方法创建。将传入的参数依次发送出来。
Observable observable = Observable.just("Hello", "Hi", "Aloha");
3.使用from(T[])/from(Iterable
String[] words = {"Hello", "Hi", "Aloha"};Observable observable = Observable.from(words);
Subscribe(订阅)
observable.subscribe(observer);// 或者:observable.subscribe(subscriber);
为什么不能颠倒顺序,即为什么不能observer.subscribe(obserable):
Observable.subscribe(Subscriber)内部核心代码
public Subscription subscribe(Subscriber subscriber) { subscriber.onStart(); onSubscribe.call(subscriber); return subscriber;}
可以看到,subscribe()做了3件事:
1.调用Subscriber.onStart()方法。
2.调用Observable中的Onsubscribe.call(Subscriber)。在这里,事件发送的逻辑开始运行。从这也可以看出,在 RxJava 中,Observable 并不是在创建的时候就立即开始发送事件,而是在它被订阅的时候,即当 subscribe() 方法执行的时候。
3.将传入的Subscriber作为Subscription返回,方便unsubscribe()。
subscribe()不完整定义的回调
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);
举例:
// 将字符串数组 names 中的所有字符串依次打印出来:String[] names = ...;Observable.from(names) .subscribe(new Action1<String>() { @Override public void call(String name) { Log.d(tag, name); } });//由指定的一个 drawable 文件 id drawableRes 取得图片,并显示在 ImageView 中,并在出现异常的时候打印 Toast 报错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(); }}).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(); }})
线程控制 — Scheduler (调度器)
- Schedulers.immediate():在当前线程运行。默认方法。
- Schedulers.newThread():启用新线程,并在新线程执行操作。
- Schedulers.io():I/O(读写文件、读写数据库、网络交互)操作所用。和newThread()差不多,区别在于io()的内部实现使用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下io()比newThread()更有效率。不要把计算工作放在io()中,可以避免创建不必要的线程。
- Schedulers.computation():计算所使用的Scheduler。该计算指CPU密集型计算,即不会被I/O等操作限制性能操作,例如图形计算。该方法使用固定线程池,大小为CPU核数。不要把I/O操作放到该方法中,否则I/O操作的等待时间会浪费CPU。
- AndroidSchedulers.mainThread():Android专有方法,指定操作在Android主线程运行。
以上方法可以使用subscribeOn()和observeOn()两个方法来控制。
- subscribeOn():指定subscribe所发生的线程,即Observable.OnSubscibe被激活时所处的线程。可叫作事件产生的线程。
- observeOn():指定Subscriber所运行的线程。可叫作事件消费的线程。
举例:
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(); }});
注:
1.通过observeOn()可以实现多次切换线程。若想要多次切换线程,只需要在要切换线程的位置调用一次observeOn()即可。例如:
Observable.just(1, 2, 3, 4) // IO 线程,由 subscribeOn() 指定 .subscribeOn(Schedulers.io()) .observeOn(Schedulers.newThread()) .map(mapOperator) // 新线程,由 observeOn() 指定 .observeOn(Schedulers.io()) .map(mapOperator2) // IO 线程,由 observeOn() 指定 .observeOn(AndroidSchedulers.mainThread) .subscribe(subscriber); // Android 主线程,由 observeOn() 指定
2.subscribeOn()的位置可以随便放,但它只能调用一次。
延伸:doOnSubscribe()
Subscriber 的 onStart() 可以用作流程开始前的初始化。然而 onStart() 由于在 subscribe() 发生时就被调用了,因此不能指定线程,而是只能执行在 subscribe() 被调用时的线程。这就导致如果 onStart() 中含有对线程有要求的代码(例如在界面上显示一个 ProgressBar,这必须在主线程执行),将会有线程非法的风险,因为有时你无法预测 subscribe() 将会在什么线程执行。
而与 Subscriber.onStart() 相对应的,有一个方法 Observable.doOnSubscribe() 。它和 Subscriber.onStart() 同样是在 subscribe() 调用后而且在事件发送前执行,但区别在于它可以指定线程。默认情况下, doOnSubscribe() 执行在 subscribe() 发生的线程;而如果在 doOnSubscribe() 之后有 subscribeOn() 的话,它将执行在离它最近的 subscribeOn() 所指定的线程。
Observable.create(onSubscribe) .subscribeOn(Schedulers.io()) .doOnSubscribe(new Action0() { @Override public void call() { progressBar.setVisibility(View.VISIBLE); // 需要在主线程执行 } }) .subscribeOn(AndroidSchedulers.mainThread()) // 指定主线程 .observeOn(AndroidSchedulers.mainThread()) .subscribe(subscriber);
变换
1.事件对象变换 map(),例如:
Observable.just("images/logo.png") // 输入类型 String .map(new Func1<String, Bitmap>() { //将String类型转换为Bitmap类型 @Override public Bitmap call(String filePath) { // 参数类型 String return getBitmapFromPath(filePath); // 返回类型 Bitmap } }) .subscribe(new Action1<Bitmap>() { @Override public void call(Bitmap bitmap) { // 参数类型 Bitmap showBitmap(bitmap); } });
2.事件队列变换 flatMap(),例如:
/** * 需求:有一个数据结构【学生】,需要打印每个学生所需要学习的所有课程的名称*/Student[] students = ...;Subscriber<Course> subscriber = new Subscriber<Course>() { @Override public void onNext(Course course) { Log.d(tag, course.getName()); } ...};Observable.from(students) .flatMap(new Func1<Student, Observable<Course>>() { @Override public Observable<Course> call(Student student) { return Observable.from(student.getCourses()); } }) .subscribe(subscriber);
3.针对Observable自身变换 compose(Transformer),例如:
/** * 需求:假设程序中有多个 Observable,并且都需要应用一组相同的 lift() 变换*/public class LiftAllTransformer implements Observable.Transformer<Integer, String> { @Override public Observable<String> call(Observable<Integer> observable) { return observable .lift1() .lift2() .lift3() .lift4(); }}...Transformer liftAll = new LiftAllTransformer();observable1.compose(liftAll).subscribe(subscriber1);observable2.compose(liftAll).subscribe(subscriber2);observable3.compose(liftAll).subscribe(subscriber3);observable4.compose(liftAll).subscribe(subscriber4);
另附几篇博客参考:
RxJava源码初探:http://www.apkbus.com/blog-705730-60688.html
RxJava全面总结:http://www.apkbus.com/blog-705730-60454.html
玩透RxJava基础知识:http://www.apkbus.com/blog-705730-60437.html
- RxJava 学习笔记(一)
- RxJava学习笔记(一)
- RxJava学习笔记(一)
- RxJava 学习笔记一
- RxJAVA学习笔记(一)
- Rxjava学习笔记(一)
- Rxjava学习笔记(一)
- RxJava学习笔记(一)--- 基础篇
- RxJava学习笔记(一)概念
- RxJava学习笔记之初识(一)
- RxJava 学习(一)
- RxJava学习(一)
- RXjava学习(一)
- Rxjava学习(一)
- RxJava学习(一),RxJava初识
- RxJava 学习之(一)
- 记Rxjava 学习(一)
- 【RxJava】的学习(一)
- oracle 与 mysql 中的函数总结
- 递归建立普通二叉树两种方式遍历
- 第四周 项目2-建设“单链表”算法库
- 让你的表格活起来-excel隔行彩条的应用
- 6-1 带头结点的单链表就地逆置
- RxJava学习笔记(一)
- 2017.9.22. 字典树
- JAVA基础集合-去除List集合中的重复值
- nginx配置账号访问
- jquery选择器
- Jfinal 连接Oracle数据库 出现FROM不到关键字的解决方法
- 环境变量是个好东西
- 欢迎使用CSDN-markdown编辑器
- Notepad++没有插件管理器(Plugin Manager)的原因以及解决方法