举例子吧。
某个地方不定期地发放个人娱乐用品,小张喜欢这些用品,希望每次都能被通知过来领取享受一把。
rxjava就是能让小张实现愿望的一个社团机构。
在以上的例子中,rxjava负责以下工作:
1.主动发起发放娱乐用品活动,每次都由rxjava主办;
2.每次搞活动时候,rxjava都派人通知小张过来领取当场享受;
所以,切回程序框架的角度,
rxjava可以用来实现这种需求场景:针对连续多次发生的事情或者多个数据进行分发给参与者处理。
例如100个图片文件的读取,每读取完一个文件后就调用参与者处理函数进行处理,参与者可能会拿着图片文件进行显示,也可能拿着文件保存到别的地方。
前面说的,仅仅是rxjava的功能,rxjava的优点肯定不仅仅是表面功能那么简单。
如果仅仅是对于多次发生的事情分发给参与者处理,那简单地用循环调用参与者的处理函数就ok了,何必用rxjava?
在此,特介绍一下rxjava的特点:
1.异步的便捷实现;
例如很简单就能实现数据读取过程在某个线程,而参与者处理数据又在另外的线程,或者在ui线程。
2.代码编写易读性;
使用起来的接口调用过程容易阅读和理解,方便后期维护。
3.数据源变换方便;
例如数据源是整数,但是订阅者需要处理的是字符串,通过rxjava可以便捷地做变换。
参考下面例子,直接提供一个OnSubscribe回调实现:
Observable observable = Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("1"); subscriber.onNext("2"); subscriber.onNext("3"); subscriber.onCompleted(); } }); just直接通过参数提供数据源来发生事件(每项数据一次事件)。
看例子:
Observable observable = Observable.just("1", "2", "3"); from从数组或者序列中提供数据源来发生事件(每项数据一次事件)。
注:函数名修改为“abservable.subscribedBy()”可能更好理解。
使用时候这么写:
Observable.from(names).subscribe(subscriber);意思是:subscriber向abservable进行subscribe,而不是abservable向subscriber进行subscribe。
也就是订阅者向提供方进行订阅动作,此时提供方会内部遍历事件/数据,依次提供给订阅者参与处理。
rx提供的线程:
Schedulers.immediate(): 直接在当前线程运行,相当于不指定线程。这是默认的 Scheduler。Schedulers.trampoline:在当前线程运行,不过不是立即运行,而是丢到队列中后面再运行。Schedulers.newThread(): 总是启用新线程,并在新线程执行操作。Schedulers.io(): I/O 操作线程。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。Schedulers.computation(): 计算线程。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。AndroidSchedulers.mainThread(),操作在 Android 主线程运行。例子:
Observable.just(1, 2, 3, 4) .subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程 .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程 .subscribe(subscriber);用map的原因:
数据源类型和订阅者处理数据类型如果一致,这样就行:
Observable.just(1, 2, 3, 4) .subscribe(new Action1<Integer>() { public void call(Integer number) { log("number:" + number); } });但是,如果遇到数据源类型和订阅者期望处理的类型不一样,就需要一个转换。
map就是为了帮忙转换而被设计出来,map在此的意思是,把数据源类型映射转换为新类型。
例如上面的例子中订阅者希望处理的是字符串,用map转换一下:
Observable.just(1, 2, 3, 4) .map(new Func1<Integer,String>(){ public String call(Integer value){return Integer.toString(value);} }) .subscribe(new Action1<String>() { public void call(String number) { log("number:" + number); } });map针对的是:一一对应地把数据源每一项数据转换为指定的类型,然后给订阅者享用。
如果,订阅者比较懒,希望处理的是每项数据里面的N项子数据,那怎么办?
例如,某个情景下订阅者处理的是每个人员姓名,那么只需用map(人员,姓名)这种方式,
某天,订阅者突然改变注意,希望处理每位人员的借阅的每一本书,这时候map就搞不定了,因为map只能一一对应地转换,没法一换多。
这时候flatMap就可以帮忙解决这个问题了。
看代码:
TPerson[] personlist = {... 演示忽略...}; Subscriber<Book> subscriber = new Subscriber<Book>() { public void onNext(Book book) { // do sth... } }; Observable.from(personlist) .flatMap(new Func1<TPerson, Observable<Book>>() { public Observable<Course> call(TPerson person) { return Observable.from(person.getBooks()); } }) .subscribe(subscriber);从代码中可以看出,faltMap的原理,其实是把数据源的每一项展开为一个子数据源,然后再给订阅者享用。
“把数据源的每一项展开为一个子数据源”这个过程,rxjava作者认为是一个“flat”的过程,所以叫flatMap。
本文结束。