RxAndroid菜鸟必入
来源:互联网 发布:淘宝网信鸽鸽具用品 编辑:程序博客网 时间:2024/05/17 21:19
为啥要学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; } }); }}
我这里把字符串转为字符串列表了,感觉没多大用哈,就是举例子嘿嘿。
- RxAndroid菜鸟必入
- RxAndroid菜鸟必入
- Okhttp3菜鸟必入
- Retrofit 菜鸟必入
- 菜鸟入职
- 菜鸟入职
- 菜鸟入职经验
- RxAndroid
- RxAndroid
- RxAndroid
- RxAndroid
- RXAndroid
- RxAndroid
- RXAndroid
- RxJava+RxAndroid+MVP入坑实践(一:基础篇)
- RxJava+RxAndroid+MVP入坑实践(一:基础篇)
- 菜鸟必学的命令
- 菜鸟必练入侵命令
- JAVA-prim 最小生成树
- Android应用内切换应用语言
- 2017 Multi-University Training Contest
- Centos 6.5 下GBrowse 2.0安装(详细版)
- 软件测试工具
- RxAndroid菜鸟必入
- PHP ---- var_dump(),echo,print_r()的区别
- 回溯法 解决二叉树中找一条和为固定数值的路径(java)
- 设计模式介绍之二:单例模式(Singleton)
- JPA-EntityManager
- Spring Boot 揭秘与实战(二) 数据存储篇
- 【系统学习SpringBoot】springBoot 入门篇
- js中判断客户端有无安装Adobe 并指引用户安装
- Python-22 文件系统:os模块