Rxjava2.x很详细的介绍
来源:互联网 发布:汕头峡山淘宝拍摄 编辑:程序博客网 时间:2024/06/03 23:04
Rxjava详解
Rxjava的优点:
- 链式调用,代码调用流程异常清晰 ,代码简洁。
- RxJava和EventBus一样也是基于观察者模式,但是使用的场景确实异步数据流的处理
- RxJava更加强大,利用操作符它可以对发出的消息进行一系列的变换
引入依赖:
compile 'io.reactivex.rxjava2:rxjava:2.0.1' compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
RxJava到底是什么?
Rxjava的是通过一种扩展的观察者设计模式来实现异步操作,跟AsyncTask和Handler类似,但是比AsyncTask和Handler更加简洁随着程序逻辑变得越来越复杂,它依然能够保持逻辑的简洁。
基本实现
(1) 创建观察者Observer,它决定事件触发的时候该有的行为。
private Observer<String> observer = new Observer<String>() { @Override public void onSubscribe(Disposable d) { //RxJava 2.0 中新增的,传递参数为Disposable ,Disposable 相当于1.x中的Subscription,调用d.dispose()解除绑定 } @Override public void onNext(String value) { } @Override public void onError(Throwable e) { //在事件处理过程中出异常时,onError()会被触发 } @Override public void onComplete() { //事件队列完结时调用该方法 } };
(2) 创建被观察者Observable,它决定什么时候以及怎样触发事件
Observable observable = Observable.create(new ObservableOnSubscribe<String>() { @Override public void subscribe(ObservableEmitter<String> e) throws Exception { e.onNext("A"); e.onNext("B"); //onError和onComplete()只能调用其中一个 e.onComplete(); } });
Observable的其他创建方式
//just方式创建 Observable<String> observable = Observable.just("Hello","A");
//fromIterable()用于集合数据,fromArray()用于数组数据方式, List<String> array1=new ArrayList<>(); array1.add("F"); array1.add("G"); Observable.fromIterable(array1).subscribe(observer);
//创建一个按固定时间间隔发射整数序列的Observable,可用作定时器。即按照固定2秒一次调用onNext()方法。 Observable<Long> interval = Observable.interval(2, TimeUnit.SECONDS);
(3) 订阅
//创建了 Observable 和 Observer 之后,再用 subscribe() 方法将它们联结起来 //被观察者订阅观察者,符合流式代码的结构 mObservable.subscribe(observer);
(5) 简洁的写法:
String[] word= new String[]{"hello", "world", "chinses"}; Disposable subscribe = Observable.fromAray(word).subscribe(new Consumer<String>() { @Override public void accept(String aLong) throws Exception { //相当于Observer的onNext() Log.i(TAG, "accept: " + aLong); } }, new Consumer<Throwable>() { @Override public void accept(Throwable throwable) throws Exception { //相当于Observer的onError() Log.i(TAG, "onError: "); } }, new Action() { @Override public void run() throws Exception { //相当于Observer的onComplete() Log.i(TAG, "onComplete: "); } }); subscribe.dispose();//取消订阅
另外我们需要明白两点:1.Observable和Observer可以做任何事情 Observable可以是一个数据库查询,Observer用来显示查询结果(传递数据);Observable可以是屏幕上的点击事件, Observer用来响应点击事件(传递事件);Observable可以是一个网络请求,Observer用来显示请求结果。2.Observable和Observer是独立于中间的变换过程的。 在Observable和Observer中间可以增减任何数量的操作符。整个系统是高度可组合的,操作数据是一个很简单的过程
操作符:
作用:将事件序列中的对象或整个序列进行加工处理,转换层不同的事件或事件序列
- filter() :可以对Observable流程的数据进行一层过滤处理,返回一个新的Observable,filter()返回为false的值将不会发出到Subscriber。
Observable.just("A").map(new Function<String, Integer>() { @Override public Integer apply(String s) throws Exception { return s.length(); } }).filter(new Predicate<Integer>() { @Override public boolean test(Integer integer) throws Exception { return integer != 10; } }).subscribe(new Consumer<Integer>() { @Override public void accept(Integer integer) throws Exception { Log.i(TAG, "accept: " + integer); } });
- map(): 事件对象的直接变换,一个Observable对象上可以多次使用map操作符
Observable.just("images/logo.png") // 输入类型 String .map(new Function<String, Bitmap>() { @Override public Bitmap apply(String filePath) { // 参数类型 String return getBitmapFromPath(filePath); // 返回类型 Bitmap } }).subscribe(new Consumer<Bitmap>() { @Override public void accept(Bitmap bitmap) throws Exception { showBitmap(bitmap); } });
- flatMap():flatMap() 和 map() 有一个相同点:它也是把传入的参数转化之后返回另一个对象,不同的是, flatMap() 中返回的是个 Observable 对象。
//有方法根据输入的字符串返回一个List集合信息 Observable<List<String>> query(String text); //假如不用flatMap()我们应该这样写: query("message") .subscribe(new Function<List<String>>() { @Override public void apply(List<String> mLists) { Observable.fromIterable(mLists) .subscribe(new Consumer<String>() { @Override public void accept(String message) { log.i(TAG,message); } }); } });
使用flatMap()这样写:
query("Hello, world!") .flatMap(new Function<List<String>, Observable<String>>() { @Override public Observable<String> apply(List<String> urls) { return Observable.from(urls); } }) .subscribe(new Consumer<String>() { @Override public void accept(String message) { log.i(TAG,message); } });
扩展:嵌套的异步请求,第一个网络请求获取第二个网络请求所需要的参数
networkClient.token() // 返回 Observable<String>,在订阅时请求 token,并在响应后发送 token .flatMap(new Function<String, Observable<Messages>>() { @Override public Observable<Messages> apply(String token) { // 返回 Observable<Messages>,在订阅时请求消息列表,并在响应后发送请求到的消息列表 return networkClient.messages(token); } } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<Messages>() { @Override public void accept(Messages messages) { // 处理显示消息列表 showMessages(messages); } });
doOnNext()
输出元素的准备工作,一般用于获取网络数据后保存到数据库的操作,因为数据库操作是耗时任务需要在子线程执行
Observable.fromIterable(arrayList).flatMap(new Function<List<String>, Observable<String>>() { @Override public Observable<String> apply(List<String> strings) throws Exception { return Observable.fromIterable(strings); } }).doOnNext(new Consumer<String>() { @Override public void accept(String s) throws Exception { Log.i(TAG, "输出元素之前的准备工作: "+s); } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<String>() { @Override public void accept(String s) throws Exception { Log.i(TAG, "accept: " + s); } });
doOnSubscribe()
Observable.doOnSubscribe() 。它和 Subscriber.onStart() 同样是在 subscribe() 调用后而且在事件发送前执行,但区别在于它可以指定线程。默认情况下, doOnSubscribe() 执行在 subscribe() 发生的线程;而如果在 doOnSubscribe() 之后有 subscribeOn() 的话,它将执行在离它最近的 subscribeOn() 所指定的线程。
Observable.fromIterable(arrayList).flatMap(new Function<List<String>, Observable<String>>() { @Override public Observable<String> apply(List<String> strings) throws Exception { Log.i(TAG, "flatMap操作: "); return Observable.fromIterable(strings); } }) .subscribeOn(Schedulers.io()) .doOnSubscribe(new Consumer<Disposable>() { @Override public void accept(Disposable disposable) throws Exception { Log.i(TAG, "事件发送之前:比如请求网络之前ProgressBar转圈操作"); } }) .subscribeOn(AndroidSchedulers.mainThread()) // 指定主线程 .observeOn(Schedulers.io()) .doOnNext(new Consumer<String>() { @Override public void accept(String s) throws Exception { Log.i(TAG, "输出元素之前的准备工作: "+s); } }) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<String>() { @Override public void accept(String s) throws Exception { Log.i(TAG, "accept: " + s); } }); //事件打印结果 com.liujian.rxjava I/MainActivity: 事件发送之前:比如请求网络之前ProgressBar转圈操作 com.liujian.rxjava I/MainActivity: flatMap操作: com.liujian.rxjava I/MainActivity: 输出元素之前的准备工作: A com.liujian.rxjava I/MainActivity: accept: A com.liujian.rxjava I/MainActivity: flatMap操作: com.liujian.rxjava I/MainActivity: accept: B com.liujian.rxjava I/MainActivity: 输出元素之前的准备工作: C com.liujian.rxjava I/MainActivity: accept: C
线程控制-Scheduler(线程调度器)
在默认情况下,即在不指定线程的情况下,RxJava遵循的是在哪个线程生产事件,就在哪个线程消费事件
- 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。
- 另外,RxAndroid 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操作将在 Android 主线程运行。
Observable.just(1,2,3,4) .subscribeOn(Schedulers.io()) //改变调用它之前代码的线程 .observeOn(AndroidSchedulers.mainThread()) //改变调用它之后代码的线程 .subscribe(new Consumer<Integer>() { @Override public void accept(Integer integer) throws Exception { //主线程显示数据 } });
线程控制-Scheduler(二)
实现线程的多次切换
注意:不同于 observeOn() , subscribeOn() 的位置放在哪里都可以,但它是只能调用一次的。
Observable.just(R.mipmap.ic_launcher) .subscribeOn(Schedulers.io())//指定Observable的操作运行在io()中 .observeOn(Schedulers.newThread())//指定map运行于newThread()中 .map(new Function<Integer, Drawable>() { @Override public Drawable apply(Integer integer)throws Exception { return getResources().getDrawable(integer); } }) .observeOn(AndroidSchedulers.mainThread())//指定Subscriber的代码运行在主线程 .subscribe(new Consumer<Drawable>() { @Override public void accept(Drawable drawable) throws Exception { iv_iamgeview.setImageDrawable(drawable); } });
- 使用场景和使用方式
- 与Retrofit结合使用 getUser(userId) //接口返回数据后把数据存到数据库,当onNext发生时,它被调用,不改变数据流。 .doOnNext(new Consumer<User>() { @Override public void accept(User user) { saveOrUpdate2Db(user); }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<User>() { @Override public void onNext(User user) { userView.setUser(user); } @Override public void onCompleted() { } @Override public void onError(Throwable error) { // Error handling ... } });
Disposable简介
在RxJava中,用它来切断Observer(观察者)与Observable(被观察者)之间的连接,当调用它的dispose()方法时,
它就会将Observer(观察者)与Observable(被观察者)之间的连接切断, 从而导致Observer(观察者)收不到事件。
注意:当切断被观察者与观察者之间的联系,Observable(被观察者)的事件却仍在继续执行。
Flowable/Subscriber
Observable和Observer的观察者模式是不支持背压的。所以,当我们使用Observable/Observer的时候,我们需要考虑的是,数据量是不是很大(官方给出以1000个事件为分界线,仅供各位参考)
背压:事件产生的速度远远快于事件消费的速度,最终导致数据积累越来越多,从而导致OOM等异常。
需要强调两点:
- 背压策略的一个前提是异步环境,也就是说,被观察者和观察者处在不同的线程环境中。
- 背压(Backpressure)并不是一个像flatMap一样可以在程序中直接使用的操作符,他只是一种控制事件流速的策略。
/* 背压(在异步过程中,由于被观察者发射数据过快,而观察者处理数据不及时, * 导致内存里堆积了太多数据,从而OOM,可以选择不同的策略处理该问题) * Flowable对应subscriber */
private void createFlowable() { Flowable<String> flowable = Flowable.create(new FlowableOnSubscribe<String>() { @Override public void subscribe(FlowableEmitter<String> e) throws Exception { if (!e.isCancelled()) { e.onNext("This"); e.onNext("is"); e.onNext("RxJava"); e.onComplete(); } } //抛弃策略 }, BackpressureStrategy.DROP); Subscriber<String> subscriber = new Subscriber<String>() { Subscription subscription; @Override public void onSubscribe(Subscription s) { subscription = s; //请求一个数据 subscription.request(1); } @Override public void onNext(String s) { Log.i(TAG, "onNext: " + s); //处理完后,再请求一个数据 subscription.request(1); } @Override public void onError(Throwable e) { Log.i(TAG, "onError: " + e.getLocalizedMessage()); } @Override public void onComplete() { Log.i(TAG, "onComplete"); //取消订阅 subscription.cancel(); } }; flowable.subscribe(subscriber); }
- Rxjava2.x很详细的介绍
- RxJava2的介绍
- Nano-X的详细介绍
- rxjava2.x
- Retrofit2和RxJava2的使用介绍一
- 3.RxJava2.x与RxJava1.x的差异对比
- Rxjava2.x 封装总结
- x-window、gnome、kde的区别和详细介绍
- Rxjava2源码解析超详细~~~
- Rxjava2.x学习记录(三)
- cocos2d-x高级UI控件详细介绍
- vert.x详细介绍,全异步框架
- RxJava1.X升级到RxJava2.X笔记
- RxJava1.X升级到RxJava2.X笔记
- RxJava2.x+ReTrofit2.x多线程下载文件
- 详细介绍spring的事物属性,很详细
- Android详细的登录注册功能MVP+Rxjava2.0+Retrofit2.0相结合的实战篇章
- gdb介绍很详细的blog
- 安装源代码版本php7
- 洛谷 P1522 牛的旅行 Cow Tours(Floyd, 并查集)
- js快速排序
- ATP的开学第一个月
- [poj2524]Ubiquitous Religions
- Rxjava2.x很详细的介绍
- [BZOJ2326][HNOI2011]数学作业(矩乘)
- js归并排序
- POJ 2051 Argus
- 从零开始写Python爬虫 --- 1.1 requests库的安装与使用
- Bootstrap初步了解 起步 基本模板
- [LintCode]175.翻转二叉树
- js封装cookie函数
- 通过行为参数传递代码