初探RxJava.docx
- 文档编号:30617341
- 上传时间:2023-08-18
- 格式:DOCX
- 页数:17
- 大小:286.20KB
初探RxJava.docx
《初探RxJava.docx》由会员分享,可在线阅读,更多相关《初探RxJava.docx(17页珍藏版)》请在冰豆网上搜索。
初探RxJava
初探RxJava
1.RxJava是什么?
“alibraryforcomposingasynchronousandevent-basedprogramsusingobservablesequencesfortheJavaVM”(一个在JavaVM上使用可观测的序列来组成异步的、基于事件的程序的库)。
—RxJava在GitHub主页上的自我介绍
一个扩展的观察者模式
一个异步数据流
观察者模式是一个观察者(observer或者subscriber)和一个被观察者(observable),观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。
这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
观察者模式:
Observable发出事件
Subscrible订阅事件
传统的观察者模式有有明显缺点导致一个被观察者发出的事件如果发生异常后面的事件也就无法正常发出或被观察者捕获:
1.无法获知事件的终止
2.没有事件异常处理机制
RxJava的观察者模式典型写法是这样的:
observable.subscribe(observer);
//或者:
observable.subscribe(subscriber);
2.RxJava的基本实现
基于以上的概念,RxJava的基本实现主要有三点:
1)创建Observer
Observer即观察者,它决定事件触发的时候将有怎样的行为。
RxJava中的Observer接口的实现方式:
Observer
@Override
publicvoidonNext(Strings){
Log.d(tag,"Item:
"+s);
}
@Override
publicvoidonCompleted(){
Log.d(tag,"Completed!
");
}
@Override
publicvoidonError(Throwablee){
Log.d(tag,"Error!
");
}
};
除了Observer接口之外,RxJava还内置了一个实现了Observer的抽象类:
Subscriber。
Subscriber对Observer接口进行了一些扩展,但他们的基本使用方式是完全一样的:
Subscriber
@Override
publicvoidonNext(Strings){
Log.d(tag,"Item:
"+s);
}
@Override
publicvoidonCompleted(){
Log.d(tag,"Completed!
");
}
@Override
publicvoidonError(Throwablee){
Log.d(tag,"Error!
");
}
};
2)创建Observable
Observable即被观察者,它决定什么时候触发事件以及触发怎样的事件。
RxJava使用create()方法来创建一个Observable,并为它定义事件触发规则:
Observableobservable=Observable.create(newObservable.OnSubscribe
@Override
publicvoidcall(Subscriber
superString>subscriber){
subscriber.onNext("Hello");
subscriber.onNext("Hi");
subscriber.onNext("Aloha");
subscriber.onCompleted();
}
});
可以看到,这里传入了一个OnSubscribe对象作为参数。
OnSubscribe会被存储在返回的Observable对象中,它的作用相当于一个计划表,当Observable被订阅的时候,OnSubscribe的call()方法会自动被调用,事件序列就会依照设定依次触发(对于上面的代码,就是观察者Subscriber将会被调用三次onNext()和一次onCompleted())。
这样,由被观察者调用了观察者的回调方法,就实现了由被观察者向观察者的事件传递,即观察者模式。
3)Subscribe(订阅)
创建了Observable和Observer之后,再用subscribe()方法将它们联结起来,整条链子就可以工作了。
代码形式很简单:
observable.subscribe(observer);
//或者:
observable.subscribe(subscriber);
1
2
3
4
这里的subscrible有点怪,有点像observable订阅了subscriber,就像杂志订阅了读者一样。
我想是基于作者对于流失API的设计,当然也可以取名字为subscribeBy.
4)场景示例
设有这样一个需求:
界面上有一个自定义的视图imageCollectorView,它的作用是显示多张图片,并能使用addImage(Bitmap)方法来任意增加显示的图片。
现在需要程序将一个给出的目录数组File[]folders中每个目录下的png图片都加载出来并显示在imageCollectorView中。
需要注意的是,由于读取图片的这一过程较为耗时,需要放在后台执行,而图片的显示则必须在UI线程执行。
常用的实现方式有多种,我这里贴出其中一种:
newThread(){
@Override
publicvoidrun(){
super.run();
for(Filefolder:
folders){
File[]files=folder.listFiles();
for(Filefile:
files){
if(file.getName().endsWith(".png")){
finalBitmapbitmap=getBitmapFromFile(file);
getActivity().runOnUiThread(newRunnable(){
@Override
publicvoidrun(){
imageCollectorView.addImage(bitmap);
}
});
}
}
}
}
}.start();
而使用RxJava的写法是这样的:
Observable.from(folders)
.flatMap(newFunc1
@Override
publicObservable
returnObservable.from(file.listFiles());
}
})
.filter(newFunc1
@Override
publicBooleancall(Filefile){
returnfile.getName().endsWith(".png");
}
})
.map(newFunc1
@Override
publicBitmapcall(Filefile){
returngetBitmapFromFile(file);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(newAction1
@Override
publicvoidcall(Bitmapbitmap){
imageCollectorView.addImage(bitmap);
}
});
3.RxJava的异步数据处理
指定被观察者生产数据所在的线程
指定订阅者接受数据所在的线程
强大的数据处理能力
先给大家一个实例,假设/user接口并不能直接访问,而需要填入一个在线获取的token,代码应该怎么写?
Callback方式,可以使用嵌套的Callback:
@GET("/token")
publicvoidgetToken(Callback
@GET("/user")
publicvoidgetUser(@Query("token")Stringtoken,@Query("userId")StringuserId,Callback
...
getToken(newCallback
@Override
publicvoidsuccess(Stringtoken){
getUser(token,userId,newCallback
@Override
publicvoidsuccess(Useruser){
userView.setUser(user);
}
@Override
publicvoidfailure(RetrofitErrorerror){
//Errorhandling
...
}
};
}
@Override
publicvoidfailure(RetrofitErrorerror){
//Errorhandling
...
}
});
倒是没有什么性能问题,可是迷之缩进毁一生,据说做过大项目的人应该更懂,而使用RxJava的话,代码是这样的:
@GET("/token")
publicObservable
@GET("/user")
publicObservable
...
getToken()
.flatMap(newFunc1
@Override
publicObservable
returngetUser(token,userId);
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(newObserver
@Override
publicvoidonNext(Useruser){
userView.setUser(user);
}
@Override
publicvoidonCompleted(){
}
@Override
publicvoidonError(Throwableerror){
//Errorhandling
...
}
});
1)数据处理
-方便对数据进行各种变换操作
-内置丰富的operators
-自定义operator
eg:
数据源返回一个一二三的整数数组,我们想把它转换成一个字符串数组
observable.just(1,2,3)
.map(newFunc1(){
@Override
publicStringcall(Integerinteger){
returnInteger.toString(integer));
}
})
.subscribe(newAction1
@Override
publicvoidcall(Stringstring){
System.out.println(string);
}
});
A.RxJava的操作符:
创建Observablecreatejustfrom
变换ObservablemapflatMap
过滤Observablefilterfirstlast
合并Observablemergezip
聚合函数Observablereducecount
…
下面我们来看一个flatMap的例子:
首先假设这么一种需求:
假设有一个数据结构『学生』,现在需要打印出一组学生的名字。
实现方式很简单:
Student[]students=...;
Subscriber
@Override
publicvoidonNext(Stringname){
Log.d(tag,name);
}
...
};
Observable.from(students)
.map(newFunc1
@Override
publicStringcall(Studentstudent){
returnstudent.getName();
}
})
.subscribe(subscriber);
很简单。
那么再假设:
如果要打印出每个学生所需要修的所有课程的名称呢?
(需求的区别在于,每个学生只有一个名字,但却有多个课程。
)首先可以这样实现:
Student[]students=...;
Subscriber
@Override
publicvoidonNext(Studentstudent){
List
for(inti=0;i Coursecourse=courses.get(i); Log.d(tag,course.getName()); } } ... }; Observable.from(students) .subscribe(subscriber); 依然很简单。 那么如果我不想在Subscriber中使用for循环,而是希望Subscriber中直接传入单个的Course对象呢(这对于代码复用很重要)? 用map()显然是不行的,因为map()是一对一的转化,而我现在的要求是一对多的转化。 那怎么才能把一个Student转化成多个Course呢? 这个时候,就需要用flatMap()了: Student[]students=...; Subscriber @Override publicvoidonNext(Coursecourse){ Log.d(tag,course.getName()); } ... }; Observable.from(students) .flatMap(newFunc1 @Override publicObservable returnObservable.from(student.getCourses()); } }) .subscribe(subscriber); 从上面的代码可以看出,flatMap()和map()有一个相同点: 它也是把传入的参数转化之后返回另一个对象。 但需要注意,和map()不同的是,flatMap()中返回的是个Observable对象,并且这个Observable对象并不是被直接发送到了Subscriber的回调方法中。 flatMap()的原理是这样的: 1.使用传入的事件对象创建一个Observable对象;2.并不发送这个Observable,而是将它激活,于是它开始发送事件;3.每一个创建出来的Observable发送的事件,都被汇入同一个Observable,而这个Observable负责将这些事件统一交给Subscriber的回调方法。 这三个步骤,把事件拆成了两级,通过一组新创建的Observable将初始的对象『铺平』之后通过统一路径分发了下去。 而这个『铺平』就是flatMap()所谓的flat。 flatMap示意图: C.然后就是变换的原理: Observable.subscribe(Subscriber)的内部实现是这样的(仅核心代码): //注意: 这不是subscribe()的源码,而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。 //如果需要看源码,可以去RxJava的GitHub仓库下载。 publicSubscriptionsubscribe(Subscribersubscriber){ subscriber.onStart(); onSubscribe.call(subscriber); returnsubscriber; } 可以看到,subscriber()做了3件事: 1.调用Subscriber.onStart()。 这个方法在前面已经介绍过,是一个可选的准备方法。 2.调用Observable中的OnSubscribe.call(Subscriber)。 在这里,事件发送的逻辑开始运行。 从这也可以看出,在RxJava中,Observable并不是在创建的时候就立即开始发送事件,而是在它被订阅的时候,即当subscribe()方法执行的时候。 3.将传入的Subscriber作为Subscription返回。 这是为了方便unsubscribe(). 这些变换虽然功能各有不同,但实质上都是针对事件序列的处理和再发送。 而在RxJava的内部,它们是基于同一个基础的变换方法: lift(Operator)。 首先看一下lift()的内部实现(仅核心代码): //注意: 这不是lift()的源码,而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。 //如果需要看源码,可以去RxJava的GitHub仓库下载。 public extendsR,? superT>operator){ returnObservable.create(newOnSubscribe @Override publicvoidcall(Subscribersubscriber){ SubscribernewSubscriber=operator.call(subscriber); newSubscriber.onStart(); onSubscribe.call(newSubscriber); } }); } 这段代码很有意思: 它生成了一个新的Observable并返回,而且创建新Observable所用的参数OnSubscribe的回调方法call()中的实现竟然看起来和前面讲过的Observable.subscribe()一样! 然而它们并不一样哟~不一样的地方关键就在于第二行onSubscribe.call(subscriber)中的onSubscribe所指代的对象不同 subscribe()中这句话的onSubscribe指的是Observable中的onSubscribe对象,这个没有问题,但是lift()之后的情况就复杂了点。 当含有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()过程,有点像一种代理机制,通过事件拦截和处理实现事件序列的变换。 2)Scheduler: 默认情况下RxJava中生产者和订阅者在当前线程下运行,Scheduler就是方便切换生产者和订阅者的线程。 Schedulers: -Schdulers.immediate() -Schdulers.newThead() -Sputation() -Schdulers.io() -AndoridSchdulers.mainThead() A.Scheduler的API 上代码: Observable.just(1,2,3,4)//IO线程,由subscribeOn()指定 .subscribeOn(Schedulers.io()) .observeOn(Schedulers.newThread()) .ma
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 初探 RxJava