RxJava & Retrofit 初探
来源:互联网 发布:导入数据load from 编辑:程序博客网 时间:2024/05/16 05:44
年后一直想学习新的技术,但是公司项目一直很紧,没有太多时间去学习,只能晚上回去后看一点,零零碎碎的学习总是容易忘记,还是博客记录一下比较好。2017加油!!
RxJava是什么
一个实现异步操作的库。
RxJava 的异步实现,是通过一种扩展的观察者模式来实现的。
一个响应式编程框架。
无论逻辑多复杂,都能保持代码的简洁度。
观察者模式
举个栗子,拿订报纸来说,订阅报纸的人(观察者)订阅了人民日报(建立订阅关系),人民日报报社(被观察者)出版新报纸就会向订报纸的人发报纸(发送事件)。
- RxJava 的观察者模式
RxJava 有四个基本概念:Observable (被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。
Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。
RxJava响应式编程
响应式编程就是与异步数据流交互的编程范式。
单击事件就是一个异步事件流,你可以观察这个流,也可以基于这个流做一些自定义操作。响应式就是基于这种想法。你能够创建所有事物的数据流,而不仅仅只是单击和悬停事件数据流。
最重要的是,有一堆的函数能够创建(create)任何流,也能将任何流进行组合(combine)和过滤(filter)。 这正是“函数式”的魔力所在。一个流能作为另一个流的输入(input),甚至多个流也可以作为其它流的输入。你能合并(merge)两个流。你还能通过过滤(filter)一个流得到那些你感兴趣的事件。你能将一个流中的数据映射(map)到一个新的流中。
流是整个响应式编程体系中的核心!!
举个栗子,有一条生产手机的流水线,若干流水线的操作工,还有一个对生产结果感兴趣的产品经理。产品经理启动流水线,操作工对拿到的材料进行各种处理,添点零部件呀什么的,最后给产品经理。
可以抽象出来一个流程:
原料 ——>操作工1—–>操作工2—–>…..操作工n–>产品经理
Observable -> Operator 1 -> Operator 2 -> Operator 3 -> Subscriber
操作工-> 操作符。既要各司其职的完成各种工作,同时也要保证事件的处理
永远处于流水线上,这也是RxJava响应式编程的关键点。subscribe() 让一个 Observer (即观察者)去订阅一个 Observable。若没有这一步整个流水线都无法启动。
需要最大程度的确保产品经理已经完成的工作不需要再做修改,Subscriber 的工作量尽量小。
基本使用
创建观察者
- 创建Observer ,即观察者,它决定事件触发的时候将有怎样的行为。
Observer observer= new Observer<String>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { Log.d(TAG,e.getMessage); } @Override public void onNext(String s) { Log.d(TAG,s); } };
- 创建Subscriber
RxJava还内置了一个实现了 Observer 的抽象类:Subscriber 。
Subscriber subscriber= new Subscriber<String>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { Log.d(TAG,e.getMessage()); } @Override public void onNext(String s) { Log.d(TAG,s); } }; };
Subscriber 对 Observer 接口进行了一些扩展,在 subscribe 过程中,Observer 会先被转换成一个 Subscriber 再使用。所以在事件正常触发时执行的是 subscriber 的 onNext 方法,错误时执行的也是 subscriber 的 onError方法 。基本使用时 Observer 和 Subscriber 相同。
创建被观察者 Observable
Observable 决定什么时候触发事件以及触发怎样的事件。
- 直接使用 create 方法进行创建。
这里传入 OnSubscribe 作为参数,OnSubscribe 会被存储在返回的 Observable 对象中,它的作用相当于一个计划表,当 Observable 被订阅的时候,OnSubscribe 的 call() 方法会自动被调用,事件序列就会依照设定依次触发。
Observable observable=Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("Hello"); subscriber.onCompleted(); } });
- just(T…): 将传入的参数依次发送出来。
Observable observable = Observable.just("Hello", "Hi", "Aloha");
- from(T[]) / from(Iterable
String[] words = {"Hello", "Hi", "Aloha"};Observable observable = Observable.from(words);
创建订阅关系 Subscribe
使用 subscribe() 方法即可实现订阅。
observable.subscribe(observer);// 或者:observable.subscribe(subscriber);
建立订阅关系以后,observable 发出事件内容,该例子发出 Hello 字符串,调用的 call 方法是观察者 subscriber 的回调方法,
打印被观察者传递过来的字符串 Hello 。
线程切换
在不指定线程的情况下, RxJava 遵循的是线程不变的原则,即:在哪个线程调用 subscribe(),就在哪个线程生产事件;在哪个线程生产事件,就在哪个线程消费事件。如果需要切换线程,就需要用到 Scheduler (调度器)。
下面是几个常用的内置的 Scheduler :
- Schedulers.newThread(): 总是启用新线程,并在新线程执行操作。
- Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。
- Schedulers.computation(): 计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
- Android 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操作将在 Android 主线程运行。
使用 subscribeOn() 和 observeOn() 两个方法来对线程进行控制。
- subscribeOn(): 指定 subscribe() 所发生的线程,即 Observable.OnSubscribe 被激活时所处的线程,或者叫做事件产生的线程。
- observeOn(): 指定 Subscriber 所运行在的线程,或者叫做事件消费的线程。
Observable.just(1, 2, 3, 4) .subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程 .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程 .subscribe(new Action1<Integer>() { @Override public void call(Integer number) { Log.d(tag, "number:" + number); } });
Observable.just(1, 2, 3, 4)为顺序发出1,2,3,4四个事件,这四个事件都在IO线程发送,打印数字在主线程。subscribeOn(Scheduler.io()) 和 observeOn(AndroidSchedulers.mainThread()) 的使用方式,适用于多数的“后台线程取数据,主线程显示”的程序策略。
特别解释一下 Action1 ,Action1 是 RxJava 的一个接口,它只有一个方法 call(),包含一个参数;由于 onCompleted() 方法也是无参无返回值的,因此 Action1 可以被当成一个包装对象,将 onCompleted() 的内容打包起来将自己作为一个参数传入 subscribe() 以实现不完整定义的回调。
通过 observeOn() 的多次调用,程序实现了线程的多次切换。不过,subscribeOn() 的位置放在哪里都可以,但是只能调用一次。
一行代码切换线程,神奇不?还有更爽的,就是接下来要说的变换。
变换
变换,就是将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列。
- map
map() 是一对一的转化,将事件A转换为事件B。
Observable.just("images/logo.png") // 输入类型 String .map(new Func1<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); } });
通过Func1
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);
Observable.from 为输入一个集合 students,每次输出一个集合中的元素 student ,flatMap 将传入的 student 对象创建一个 Observable 对象,该对象并不被传递给 subscriber ,只是激活并发送事件(每个学生修的每一们课),然后将所有的事件都汇给同一个 Observable ,该 Observable 负责将收集到的事件传递给 subscriber 的回调方法。
把事件拆成了两级,通过一组新创建的 Observable 将初始的对象『铺平』之后通过统一路径分发了下去。而这个『铺平』就是 flatMap() 所谓的 flat。
Retrofit
Retrofit就是对okhttp做了一层封装。把网络请求都交给了Okhttp,我们只需要通过简单的配置就能使用retrofit来进行网络请求了。
- 导包
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'//Retrofit2所需要的包compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'//ConverterFactory的Gson依赖包compile 'com.squareup.retrofit2:converter-scalars:2.0.0-beta4'//ConverterFactory的String依赖包
假设我们请求的API是:
https://api.douban.com/v2/movie/top250
- 定义一个接口
public interface MovieService { @GET("top250") Call<MovieSubject> getTop250(@Query("count")int count,@Query("start")int start);}
- 创建一个Retrofit 对象
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.douban.com/v2/movie/") //增加返回值为String的支持 .addConverterFactory(ScalarsConverterFactory.create()) //增加返回值为Gson的支持(以实体类返回) .addConverterFactory(GsonConverterFactory.create()) //增加返回值为Oservable<T>的支持 .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build();
- 生成接口的实例对象
MovieService movieSerive = retrofit.create(RequestSerives.class);
- 得到Call对象,就可以发出网络请求啦
Call<MovieSubject> call = movieSerive getTop250(0,20);//传入请求参数call.enqueue(new Callback<MovieSubject>() { @Override public void onResponse(Call<MovieSubject> call, Response<MovieSubject> response) { } @Override public void onFailure(Call<String> call, Throwable t) { Log.e("===","失败"); }});
RxJava x Retrofit 实现网络请求
- 定义一个接口 MovieService,定义一个获取豆瓣电影的方法 getTop250,返回一个Observable对象
@GET("top250") Observable<MovieSubject> getTop250(@Query("start") int start, @Query("count") int count);
- 创建一个 retrofit 对象
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.douban.com/v2/movie/") //增加返回值为Gson的支持(以实体类返回) .addConverterFactory(GsonConverterFactory.create()) //增加返回值为Oservable<T>的支持 .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build();MovieService service=retrofit.create(MovieService.class);
- 使用
Retrofit 把请求封装进 Observable ,在请求结束后调用 onNext() 或在请求失败后调用 onError()。
getTop250(0, 20) .map(new Func1<MovieSubject, List<MovieItem>>() { @Override public List<MovieItem> call(MovieSubject movieSubject) { return movieSubject.getMovieItems(); } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<List<MovieItem>>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { toast("e.getMessage"); } @Override public void onNext(List<MovieItem> movieItems) { view.showMovie(movieItems); } });
感谢
[给 Android 开发者的 RxJava 详解]
(http://gank.io/post/560e15be2dca930e00da1083#toc_1)[RxJava 之 响应式编程]
(http://www.jianshu.com/p/fee2a68da1fc)深入浅出RxJava一:基础篇
深入浅出RxJava二:操作符
深入浅出RxJava三–响应式的好处
深入浅出RxJava四-在Android中使用响应式编程
- Rxjava、retrofit初探
- RxJava & Retrofit 初探
- 王学岗Retrofit初探(四)——与Rxjava的使用
- Retrofit+Rxjava
- Retrofit+RxJava
- Retrofit+RxJava
- Retrofit+RxJava
- Retrofit+RxJava
- RxJava+Retrofit
- rxjava+retrofit
- RxJava&Retrofit
- Retrofit+Rxjava
- Retrofit+RxJava
- RXJava & Retrofit
- Rxjava+retrofit
- rxjava+retrofit
- Rxjava & Retrofit
- retrofit+Rxjava
- Neural Relation Extraction(神经关系抽取)的两篇文章
- 关于web app rem 的使用
- CMMI(Capability Maturity Model Integration)
- VS2008 清理注册表
- ubuntu16系统上通过minicom串口连接NanoPi M3开发板
- RxJava & Retrofit 初探
- 利用两个队列实现栈---进栈和出栈
- 布局优化include与merge
- 修改文本输入框默认的placeholder的字体颜色
- ButterKnife绑定失败?android-apt没用?尝试用一下annotationProcessor
- NUC
- jps命令使用
- display:flex;巧用技巧
- 24位 位图与32位 位图差异解析