RxJava——响应式编程续
继续来学习我们的RxJava,接着前面一篇的内容,接下来我们要开始看什么是Observer和Operator。
Observer
任何订阅了Observable的东西,都可以称之为Observer;只要Observable发送了数据,所有订阅了它的Observer都会收到通知。
在我们举的会议的例子中,所有坐在那里听发言者讲话的人都是Observer。每当发言人在台上说出某些内容的时候,所有与会者都可以倾听并做出反应。
Observer有三种可以接受的事务类型:
- onNext(T) —— 当源Observable发出指定项(类型为T)时,它将会被调用。如果源Observable有多个要发出的项,它将多次被调用。
- onCompleted() —— 当源Observable发出了它的所有items之后,它会被调用。它表明Observable已经被成功完成,
- onError(Throwable) —— 当源Observab了发生错误的时候,它将会被调用。这也是一个结束事件,它提供一个Throwable,里面包含了错误的详细信息。
代码时间
DisposableObserver<Movie> disposable = movieObservable
.subscribeWith(new DisposableObserver<Movie>(){
@Override
public void onNext(Movie movie){
// 获取movie
}
@Override
public void onComplete(){
//通知事件结束
}
@Override
public void onError(Throwable e){
// 处理错误
}
})
每次observable提取Movie对象时,都会调用onNext(Movie)方法。它可以从网络,数据库,文件或任何其他来源(这并不重要)获取。重要的是订阅它的Observer将始终收到流中发生的事件的通知。
因此,如果您的数据存储中有10部电影,那么将使用10个电影对象调用onNext()方法10次。操作成功后,将调用onComplete()方法,但如果失败,将使用相应的错误对象调用onError()方法。
什么是Dispose?
上面的代码里面还有一样东西没有弄清楚,那就是DisposableObserver。
DisposableObserver只是一个Observer,可以在实现Disposable接口时进行处理。每当Observer订阅一个Observable时,就会在它们之间形成一个连接,当不需要时,它实际上需要被清除(或终止),否则会导致资源泄漏。
你还可以使用CompositeDisposable来添加所有disposable,并立即清除所有一次性用品。
Operator
接下来,又是RxJava的一个重头戏了。
RxJava 的强大之处就在于它提供了大量的操作符,操作符基本上是纯函数,用来转换或者修改可观察的数据流。
还是回到一开始的会议例子上,假设一个新的发言人要上台开始用日语发言,但是坐在那里的与会人员都只会中文,这时候我们怎么处理呢?
这时候我们就需要一个Tanslater出现,将发言者的每一句话都翻译成所有与会人员都能理解的有意义的内容。
具体的在RxJava中来看看吧。
- filter() —— 用于过滤源Observer发出的项,并创建一个新的Observable,其中只包含符合条件的项。
假设,我们的电影Observable可以给出不同评分的电影,但我们只想展示5星的电影。
movieObservable.filter(new Predicate<Moview>){
@Override
public boolean test(@NonNull Movie movie) throws Exception {
return movie.getRating() == 5;
}
}
我们可以直接使用lambda表达式来写:
movieObservable.filter(movie -> movie.getRating() == 5);
- map() —— 用于将Observable发出的项转换为完全不同的项,并创建一个包含这些修改项的新Observable
继续假设,如果我们要求显示的电影概要不能超过500个字符,那么我们可以这样来做。
Observable<Movie> movieObservable = getMovieFromDatabase();
movieObservable.map(new Function<Movie, Movie> {
@Override
public Movie apply(@NonNull Movie movie) throws Exception {
return new Movie(StringUtils.truncate(movie.getSynopsis(),500))
}
})
同样的,我们可以用lambda表达式进行简化:
movieObservable.map(movie -> new Movie(truncate(movi.getSynopsis(), 500)));
- skip() —— 用于从源Observable的开头跳过一些项,并创建一个没有这些项的新Observble。
假设,我们知道我们的电影的Observable在流的开头发出一个虚拟的Movie对象用于测试,不应该向用户显示。
movieObservable.skip(1);
- concat() —— 用于依次连接多个Observable。
还是电影的例子,我们有两个数据源获取电影——数据库和网络,我们想要先显示数据库中的电影之后再显示网络请求的电影。
Observable<Movie> database = getMoviesFromDatabase();
Observable<Movie> network = getMoviesFromNetwork();
Observable<Movie> resultObservable = Observable.concat(database, network);
这些运算符方法的返回类型也是Observable,这就意味着我们可以把这一个个多个运算符并执行很棒的操作。
movieObservable
.skip(1)
.filter(movie -> movie.getRating() == 5)
.map(movie -> truncate(movie.getSynopsis(), 500));
上面简单的四行代码, 我们跳过了流中发出的第一个测试项,如何过滤出评分5星的电影,然后将每个电影项的概要截断为500个字符,非常的简单好用。
当然,RxJava中还有许许多多其它的运算符,在这里就不一一的去介绍了,可以去官方文档去查询并熟悉。
其它概念
ObserveOn/SubscribeOn
这两个运算符也和前面所说的运算符一样,但他们有一些特殊的用途——控制RxJava中的多线程。
subscribeOn()
用于指定Observable在哪个线程执行数据的请求工作。
还是电影的例子,我们需要从网络获取电影的数据,很显然我们需要在后台线程执行,因为Android不允许你在主线程中进行耗时的网络操作。
movieObservable.subscribeOn(Schedulers.io())
.subscribe(movie -> {
//处理电影
}, throwable -> {
//处理错误
});
observeOn()
用于指定Observer处理接收到的数据的线程。
假设,你的源Observable发送数据到io线程,但在Android中IO线程是不允许处理界面UI刷新的,因此你需要将数据指定到UI线程中。
movieObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(movie -> {
// 处理movie 刷新界面
}, throwable -> {
// 处理错误
})
Schedulers
前面你已经使用了多次Schedulers了,但你可能还在疑惑他到底是什么?
简单来说,Schedulers代表要执行的操作所在的线程。
- Schedulers.io() —— 操作将会在IO线程中执行,用于网络请求、数据库事务、文件处理等
- Schedulers.computation() —— 用于计算量很大且需要在一个优化的线程中处理的事务
- Schedulers.newThread() —— 创建一个新的线程来处理事务。但我们不能无限制的创建新线程,以便可以使用线程池等技术来优化性能
- AndroidSchedulers.mainThread() —— Android的主线程
OK,学到这里,相信你已经对RxJava有所了解了。接下来还有很长的路要走,比如熟悉各个操作符的使用方式,甚至到研究原理。