RxJava

RxJava学习笔记

RxJava–简洁的异步


观察者模式

RxJava使用的是观察者模式,即采用注册或订阅方式,在被观察者发生变化时通知观察者,我们经常看到的是点击监听–View设置OnClickListener,在这里View是被观察者,OnClickListener是观察者,当View被点击时,Android FrameWork会将点击事件发送给已经注册的OnClickLinstener,观察者模式相对于反复检索状态的方式更加节省资源消耗,速度也更快。

RXJava的组成结构

RxJava有被观察者-Observable,观察者-Observer,以及订阅-subscribe,事件这四个基本概念。 Observable与Observer通过subscribe方法实现订阅,当Observable在特定的时候发出事件通知Observer。

1.Observer-观察者

RxJava中可以通过实现Observer接口和实现Observer得抽象类-Subscribe两种方式实现:

Observer<String> observer = new Observer<String>() {
@Override
public void onNext(String s) {   
}

@Override
public void onCompleted() {    
}

@Override
public void onError(Throwable e) {
}
};

或者

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中回调方法有onNext() onCompleted() onError()

  • onNext()普通执行方法,相当于onClick()
  • onCompleted()事件队列完结
  • onError() 事件队列异常

在一个正确运行的事件序列中, onCompleted() 和 onError() 有且只有一个,并且是事件序列中的最后一个。而且,onCompleted() 和 onError() 二者也是互斥的,即在队列中调用了其中一个,就不应该再调用另一个。

上面的两种实现方法实质上,在 RxJava 的 subscribe 过程中,Observer 也总是会先被转换成一个 Subscriber 再使用。但是两种方法也有一些不同:

  • 在Subscriber中增加了onStart()方法,它会在subscribe开始而且事件没有发送以前就被调用,可以用于开始准备,它是在subscribe发生的线程被调用,所以一些需要指定线程的准备工作就不能用它了。
  • Subscribe中还有一个unsubcribe方法,用于取消订阅,调用后,Subscriber将不再接收事件,在subscribe()后Observable会一直持有Subscriber的引用,如不及时释放将有可能导致内存泄漏,所以使用这个方法将避免内存泄漏的发生。一般在调用前使用isUnsubscribed()方法检查状态。
2.Observable–被观察者

RxJava中使用create()方法来创建Observable,并为它定义事件触发规则

Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello");
subscriber.onNext("World");
subscriber.onCompleted();
}
});

可以看出,call()方法中传入一个OnSubscribe对象作为参数,当 Observable 被订阅的时候,OnSubscribe 的 call() 方法会自动被调用,事件序列就会依照设定依次触发(这里是观察者Subscriber 将会被调用两次 onNext() 和一次 onCompleted())。

除了create()方法还有一些方法用于快捷创建事件队列:

  • just(T..) –看完下面的小例子就懂了

    Observable observable = Observable.just(“Hello”, “World”);
    // 将会依次调用:
    // onNext(“Hello”);
    // onNext(“World”);
    // onCompleted();

  • from(T[]) 或from(Iterable

3.Subscribe–订阅

使用subscribe()就可以将Observable和Observer链接起来了。

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

订阅或将调用onStart()方法,之后调用Observable(被观察者)的call方法,可以看出Observable是在订阅的时候发送事件,而不是在创建的时候发送。
同时,subscribe()还可以使用不完全定义的回调,小例子:

Action1<String> onNextAction = new Action1<String>() {
// onNext()
@Override
public void call(String s) {
}
};
Action1<Throwable> onErrorAction = new Action1<Throwable>() {
// onError()
@Override
public void call(Throwable throwable) {
}
};
Action0 onCompletedAction = new Action0() {
// onCompleted()
@Override
public void call() {
}
};

// 自动创建 Subscriber ,并使用 onNextAction 来定义 onNext()
observable.subscribe(onNextAction);
// 自动创建 Subscriber ,并使用 onNextAction 和 onErrorAction 来定义 onNext() 和 onError()
observable.subscribe(onNextAction, onErrorAction);
// 自动创建 Subscriber ,并使用 onNextAction、 onErrorAction 和 onCompletedAction 来定义 onNext()、 onError() 和 onCompleted()
observable.subscribe(onNextAction, onErrorAction, onCompletedAction);

上面的Action1与Action0都是RxJava的接口,只有一个有1/0个参数无返回值的call()方法。

线程控制

RaJava用于实现异步,当然得说它的线程控制咯。

在上面讲的内容中都是不指定线程,RxJava遵循:在哪个线程调用subscribe()方法就在那个线程生成,消费事件。需要切换线程就要用到Scheduler了。

Scheduler–调度器 RxJava通过它来指定代码的运行线程,RxJava中内置了以下几个Scheduler:

  • Schedulers.immediate() 在当前线程运行,默认Schedulers
  • Schedulers.newThread() 启用新线程,并在新线程中执行
  • Schedulers.io() I/O操作所使用的线程(读写文件,数据库,网络)它的行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。
  • Schedulers.computation() 计算所使用的Schedulers.这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
  • Android中专用的AndroidSchedulers.mainThread() 在主线程运行

接下来,就可以用subscribeOn()与observeOn()两个方法对线程进行控制了, subscribeOn():subscribe()所发生的线程,即Observable.OnSubscribe被激活的线程。 (内容创建所在的线程) observeOn():指定Subcriber所运行的线程。(内容消费,Next()执行所在线程)

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);
}
});

这里事件创立是在io线程,而打印数字在主线程。

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);

变换–RxJava厉害之处

变换–将事件序列中的对象或整个序列进行加工处理,处理成不同的事件或者事件序列。

map()

小例子

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也是RxJava的一个接口,用于包装有一个参数的方法。Func1是有返回值的,这与Action1()不同。

这里的map()方法就是将String 对象转换成一个Bitmap对象,返回Bitmap对象。

flatMap()

这个与map()一样是用来将传入的参数转变成另一个对象,但是与map()不同,flatMap()返回的是一个Observable对象,其原理是这样的:1. 使用传入的事件对象创建一个 Observable 对象 2. 并不发送这个 Observable, 而是将它激活,于是它开始发送事件;3. 每一个创建出来的 Observable 发送的事件,都被汇入同一个 Observable ,而这个 Observable 负责将这些事件统一交给 Subscriber 的回调方法。这三个步骤,把事件拆成了两级,通过一组新创建的 Observable 将初始的对象『铺平』之后通过统一路径分发了下去。而这个『铺平』就是 flatMap() 所谓的 flat。

Item[] itemss = ...;
Subscriber<Bitmap> subscriber = new Subscriber<Bitmap>() {
@Override
public void onNext(Bitmap bitmap) {
//处理bitmap
}
...
};
Observable.from(items)
.flatMap(new Func1<Item, Observable<Bitmap>>() {
@Override
public Observable<Bitmap> call(Item item) {
return Observable.from(student.getbitmaps());
}
})
.subscribe(subscriber);

这个小例子就是一开始利用传入Item对象创建一个Observable,然后发送事件(这里的bitmap),之后传入的Item对象一样,他们所发送的事件再统一传到一个Observable对象,之后这个Observable再交给Subscriber的回调方法next()中执行操作。

变换原理

变换就是将事件序列处理后再次发送,它们都是基于一个最基本的方法 lift(Operator)。

在 Observable 执行了 lift(Operator) 方法之后,会返回一个新的 Observable,这个新的 Observable 会像一个代理一样,负责接收原始的 Observable 发出的事件,并在处理后发送给 Subscriber。这就有点像Android中的事件拦截机制了~

线程控制原理

在了解变换原理后,我们应该可以想到变换将会执行不同的Observable,那么就可以对变换后的Observable更换线程呀。( subscribeOn() observeOn() 控制事件的产生和消费的线程。)

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() 指定

同样的,线程控制 subscribeOn()与observeOn()的原理也是lift()。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值