RxJava1.x

关于

  GitHub 主页上的自我介绍是 “a library for composing asynchronous and event-based programs using observable sequences for the Java VM”(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。
  RxJava 是异步,但它比AsyncTask / Handler/… 在逻辑上更加简洁

API

  RxJava 的异步实现,是通过一种扩展的观察者模式来实现的
  

观察者模式(Observer)

  定义对象之间一对多的关系,当一个对象被修改,其他关联对象会并得到通知并自动更新。观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式、模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。经典样例:Java的事件监听机制

RxJava2和RxJava1的区别猛戳这里

RxJava 的观察者模式

RxJava 有四个基本概念:

方法描述解释
Observable被观察者产生事件(事件源)
Observer观察者根据事件作出相应的响应
subscribe(订阅)、事件实现了Observer的抽象类
Subject(Observable + Observer)

Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer
RxJava的Observable是扩展自设计模式中的观察者模式,添加了以下几个能力:

  • onCompleted(),当没有新的可用数据时,通知Observable
  • onError(),当发生错误时,通知Observable,但不会直接将错误或异常直接抛出;
    需要注意的是,onCompleted() 和 onError() 二者也是互斥的,即在队列中调用了其中一个,就不应该再调用另一个。

Subject可以像观察者(Observer)一样订阅一个事件源,并且可以像Observable(被观察者)一样输出它们收到的事件。RxJava提供了四种不同类型的subjects:

  • PublishSubject,
  • BehaviorSubject,输出它观察到的大部分最近的Items和随后观察的Items到所有的订阅者,初始化时需要一个初始值来做为最近的Items
  • ReplaySubject,将它观察到的所有数据重复发送到所有订阅了的观察者;
  • AsyncSubject, 在整个Observable完成后,将最后观察到的Items发送给每一个订阅者;
Observable

大致如下图:

Observable生命周期包含个可能的事件 与迭代器的生命周期很类似

事件迭代器(Iterable)pull被观察者(Observable )push
得到数据T next()onNext(T)
发现错误throws ExceptiononError(Throwable)
完成!hasNext()onCompleted()

区别
在使用迭代器的时候,线程会阻塞直到他们需要的数据到来。
而Observable,是使用异步的方式将数据推送到Observer。
根据推送机制的不同,Observable分为热Observable冷Observable

  • 热Observable,当他创建时新开始执行它的职责,这样所有订阅了这个Observable的Observer就可以直接大中途观察了(但可能会丢失前面发送的数据(事件));
  • 冷Observable,只有等到有订阅(subscribes)了这个Observable的Observer才开始执行它的职责:发送数据;

RxJava 的基本实现主要有三点:

  • 1) 创建 Observer
  • 2) 创建 Observable
  • 3) Subscribe (订阅)
1.1Observer

1.1.1接口实现
RxJava 中的 Observer 接口的实现方式如下

Observer<String> observer = new Observer<String>() {
    @Override
    public void onNext(String s) {
        Log.d(tag, "Item: " + s);
    }
    @Override
    public void onCompleted() {
        Log.d(tag, "Completed!");
    }
    @Override
    public void onError(Throwable e) {
        Log.d(tag, "Error!");
    }
};

1.1.2抽象类实现
RxJava 内置了一个实现了 Observer 的抽象类:Subscriber,他们的基本使用方式是完全一样的。

Subscriber<String> subscriber = new Subscriber<String>() {
    @Override
    public void onNext(String s) {
        Log.d(tag, "Item: " + s);
    }

    @Override
    public void onCompleted() {
        Log.d(tag, "Completed!");
    }

    @Override
    public void onError(Throwable e) {
        Log.d(tag, "Error!");
    }
};

实质上,在 RxJava 的 subscribe 过程中,Observer 也总是会先被转换成一个 Subscriber 再使用。所以如果只想使用基本功能,选择 Observer 和 Subscriber 是完全一样的。

Subscriber 的扩展

扩展方法描述
onStart()它会在 subscribe 刚开始,而事件还未发送之前被调用,可以用于做一些准备工作,例如数据的清零或重置。这是一个可选方法,默认情况下它的实现为。如果对准备工作的线程有要求(例如弹出一个显示进度的对话框,这必须在主线程执行), onStart() 就不适用了,因为它总是在 subscribe 所发生的线程被调用,而不能指定线程。要在指定的线程来做准备工作,可以使用 doOnSubscribe() 方法
unsubscribe()用于取消订阅。在这个方法被调用后,Subscriber 将不再接收事件。一般在这个方法调用前,可以使用 isUnsubscribed() 先判断一下状态。unsubscribe() 这个方法很重要,因为在 subscribe() 之后, Observable 会持有 Subscriber 的引用,这个引用如果不能及时被释放,将有内存泄露的风险。所以要在不再使用的时候尽快在合适的地方(例如 onPause() onStop() 等方法中)调用 unsubscribe() 来解除引用关系,以避免内存泄露的发生。

doOnSubscribe()
Subscriber.onStart() 相对应的,有一个方法 Observable.doOnSubscribe() 。它和 Subscriber.onStart() 同样是在 subscribe() 调用后而且在事件发送前执行,但区别在于它可以指定线程。默认情况下, doOnSubscribe() 执行在 subscribe() 发生的线程;而如果在 doOnSubscribe() 之后有 subscribeOn() 的话,它将执行在离它最近的 subscribeOn() 所指定的线程。
示例:

Observable.create(onSubscribe)
.subscribeOn(Schedulers.io())
.doOnSubscribe(new Action0() {
    @Override
    public void call() {
        progressBar.setVisibility(View.VISIBLE); // 需要在主线程执行
    }
})
.subscribeOn(AndroidSchedulers.mainThread()) // 指定主线程
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
1.2Observable

构造方法

构造方法描述
create(subscribe)需要一个subscribe作为参数来构造
Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        subscriber.onNext("Hello");
        subscriber.onNext("Hi");
        subscriber.onNext("RxJava");
        subscriber.onCompleted();
    }
});
构造方法描述
from(list)将传入的数组或 Iterable 拆分成具体对象后,依次发送出来,和前面的create作用类似
String[] words = {"Hello", "Hi", "RxJava"};
Observable observable = Observable.from(words);
// 将会依次调用:
// onNext("Hello");
// onNext("Hi");
// onNext("RxJava");
// onCompleted();
构造方法描述
just(funnction)用来接收从一个方法的返回值(最多可以有9个参数),如果返回的是List,它不会去逐个遍历List的Items,而是直接输出整个List,和前面的create作用类似
Observable observable = Observable.just("Hello", "Hi", "RxJava");
// 将会依次调用:
// onNext("Hello");
// onNext("Hi");
// onNext("RxJava");
// onCompleted();
构造方法描述
empty()不输出数据,但可以正常结束
never()不输出数据,并且不会终止
throw()不输出数据,但在发生错误时终止
interval()创建一个按固定间隔发送整数序列的Observable
timer()创建一个Observable在给定的延迟后发送一个特殊的值
1.3Subscribe

创建了 Observable 和 Observer 之后,再用 subscribe() 方法将它们联结起来,整条链子就可以工作了

observable.subscribe(observer);
// 或者:
observable.subscribe(subscriber);

其内部实现是这样的(仅核心代码)

public Subscription subscribe(Subscriber subscriber) {
    subscriber.onStart();
    onSubscribe.call(subscriber);
    return subscriber;
}

大致图片如下:

在 RxJava 的默认规则中,事件的发出和消费都是在同一个线程的。而要实现异步,则需要用到 RxJava 的另一个概念: Scheduler

线程的调度(Scheduler)

在不指定线程的情况下, RxJava 遵循的是线程不变的原则,即:在哪个线程调用 subscribe(),就在哪个线程生产事件;在哪个线程生产事件,就在哪个线程消费事件。如果需要切换线程,就需要用到 Scheduler (调度器)。RxJava提供了5种类型的调度者

调度器描述
Schedulers.io()使用线程池来为IO操作进行调度,内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。
Schedulers.computation()与IO无关的计算型调度,这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
Schedulers.immediate()在当前线程中快速开始某项操作,相当于不指定线程。是方法:timeout(),timeInterval等的默认调度器
Schedulers.newThread()总是启用新线程,并在新线程执行操作
Schedulers.trampoline()为一些不需要立即执行的任务进行调度,会依次执行队列里的任务,是方法:repeat(),retry()的默认调度器
AndroidSchedulers.mainThread()Android 还有一个专用的,它指定的操作将在 Android 主线程运行

有了 Scheduler ,就可以使用 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);
            }
        });

RxJava的操作符

RxJava 提供了对事件序列进行变换的支持:将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列
过滤操作

过滤方法描述
filter()过滤掉不需要的数据,只有返回true 的数据才会被使用;
throttleFirst()常用作去抖动过滤,例如按钮的点击监听器
take(int n)只取返回数据中的前n个,skip(int n)跳过前n个数据;
takeLast(int n)只取数据的最后n个,skipLast(int n)
distinct()会帮助我们处理重复的数据,但如果数据太大的话,内存需要比较大
distinctUntilChanged()只有当新数据与先前的不同,才会输出
first(),last()
firstOrDefault()lastOrDefault,如果Observable没有输出任何数据时,我们可以给一个默认值
elementAt(int n)输出第n个位置上的数据(从0 开始)
timeout()如果在给定时间间隔内,没有输出有效数据,则会执行onError()
delay()用于事件流中,延迟一段时间再发送来自Observable的结果

映射变换操作
针对事件序列的处理和再发送

映射变换方法描述
map()事件对象的直接变换用来映射简单的数据
flatMap()把事件拆成了两级,通过一组新创建的 Observable 将初始的对象『铺平』之后通过统一路径分发了下去。而这个『铺平』就是 flatMap() 所谓的 flat。
由于可以在嵌套的 Observable 中添加异步代码, flatMap() 也常用于嵌套的异步操作,例如嵌套的网络请求
lift()像一种代理机制,通过事件拦截和处理实现事件序列的变换。在 Observable 执行了 lift(Operator) 方法之后,会返回一个新的 Observable,这个新的 Observable 会像一个代理一样,负责接收原始的 Observable 发出的事件,并在处理后发送给 Subscriber。
两次和多次的 lift() 同理
compose()对 Observable 整体的变换
observable1.compose(liftAll).subscribe(subscriber1);
concatMap()解决了fmp的交错的问题
flatMapIterable()将生成的Iterable与Items进行对应起来(类似于key-value)
switchMap()这几个方法都是将输入的数据以一种新的形式输出
Scan()类似于一个累加的方法,后一个item是前面item的后再加上原来的item
GroupBy()
buffer(int n)将数据作为列表(每n个数据作为一个列表)输出而不是单个的Items
cast()类似于map()

合并操作

合并方法描述
merge()可以将多个输入整合成一个输出(并不会合并Items)
zip()可以将多个输入整合成一个输出(会合并Items)

重试操作

重试方法描述
retryWhen()当接收到onError()事件时,触发重新订阅(发生某些错误时,需要做什么工作)
repeat()当接收到onComplete()事件时,触发重新订阅

数据变换中线程的自由切换

Observable.just(1, 2, 3, 4) // IO 线程,由 subscribeOn() 指定
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.newThread())
    .map(mapOperator) // 新线程,由 observeOn() 指定
    .observeOn(Schedulers.io())
    .map(mapOperator2) // IO 线程,由 observeOn() 指定
    .observeOn(AndroidSchedulers.mainThread) 
    .subscribe(subscriber);  // Android 主线程,由 observeOn() 指定
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值