RxJava操作符(09-算术/聚合操作&连接操作)
转载请标明出处:
http://blog.csdn.net/xmxkf/article/details/51692493
本文出自:【openXu的博客】
目录:
算术&聚合
1. Count
Count操作符将一个Observable转换成一个发射单个值的Observable,这个值表示原始Observable发射的数据的数量。
如果原始Observable发生错误终止,Count不发射数据而是直接传递错误通知。如果原始Observable永远不终止,Count既不会发射数据也不会终止。
示例代码:
Observable.from(new String[] { "one", "two", "three" })
.count()
.subscribe(integer->Log.v(TAG, "count:"+integer));
Observable.from(new String[] { "one", "two", "three" })
.countLong()
.subscribe(aLong->Log.v(TAG, "countLong:"+aLong));
输出:
count:3
countLong:3
2. Concat
concat操作符会依次发射多个Observable的数据,第一个Observable发射的所有数据在第二个Observable发射的任何数据前面,以此类推,直到前面一个Observable终止,Concat才会订阅额外的一个Observable。
Merge操作符也差不多,它结合两个或多个Observable的发射物,但是数据可能交错,而Concat不会让多个Observable的发射物交错。
示例代码:
//还有一个实例方法叫concatWith,这两者是等价的:Observable.concat(a,b)和a.concatWith(b)
Observable.concat(
Observable.interval(100,TimeUnit.MILLISECONDS).take(4),
Observable.interval(200,TimeUnit.MILLISECONDS).take(5))
.subscribe(aLong -> Log.v(TAG, "concat:"+aLong));
输出:
concat:0
concat:1
concat:2
concat:3concat:0
concat:1
concat:2
concat:3
concat:4
3. Reduce
Reduce操作符对原始Observable发射数据的第一项应用一个函数,然后再将这个函数的返回值与第二项数据一起传递给函数,以此类推,持续这个过程知道原始Observable发射它的最后一项数据并终止,此时Reduce返回的Observable发射这个函数返回的最终值。
注意如果原始Observable没有发射任何数据,reduce抛出异常IllegalArgumentException。
在其它场景中,这种操作有时被称为累积,聚集,压缩,折叠,注射等。
示例代码:
Observable.just(1,2,3,4)
.reduce(new Func2<Integer, Integer, Integer>() {
//integer为前面几项只和,integer2为当前发射的数据
@Override
public Integer call(Integer integer, Integer integer2) {
Log.v(TAG, "integer:"+integer+" integer2:"+integer2);
return integer+integer2;
}
}).subscribe(integer -> Log.v(TAG, "reduce:"+integer));
输出:
integer:1 integer2:2
integer:3 integer2:3
integer:6 integer2:4
reduce:10
连接操作
1. Publish
Publish 操作符将普通的Observable转换为可连接的Observable(ConnectableObservable),ConnectableObservable是Observable的子类。 可连接的Observable (connectable Observable)与普通的Observable差不多,不过它并不会在被订阅时开始发射数据,而是直到使用了Connect操作符时才会开始,这样可以更灵活的控制发射数据的时机。
注意:如果一个ConnectableObservable已经开始发射数据,再对其进行订阅只能接受之后发射的数据,订阅之前已经发射过的数据就丢失了。
示例代码:
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
Observable<Long> obs = Observable.interval(1, TimeUnit.SECONDS).take(5);
//使用publish操作符将普通Observable转换为可连接的Observable
ConnectableObservable<Long> connectableObservable = obs.publish();
//第一个订阅者订阅,不会开始发射数据
connectableObservable.subscribe(new Subscriber<Long>() {
@Override
public void onCompleted() {
Log.v(TAG, "1.onCompleted");
}
@Override
public void onError(Throwable e) {
Log.v(TAG, "1.onError");
}
@Override
public void onNext(Long along) {
Log.v(TAG, "1.onNext:"+along+"->time:"+ sdf.format(new Date()));
}
});
//开始发射数据
Log.v(TAG, "start time:" + sdf.format(new Date()));
connectableObservable.connect();
//第二个订阅者延迟2s订阅,这将导致丢失前面2s内发射的数据
connectableObservable
.delaySubscription(2, TimeUnit.SECONDS)
.subscribe(new Subscriber<Long>() {
@Override
public void onCompleted() {
Log.v(TAG, "2.onCompleted");
}
@Override
public void onError(Throwable e) {
Log.v(TAG, "2.onError");
}
@Override
public void onNext(Long along) {
Log.v(TAG, "2.onNext:"+along+"->time:"+ sdf.format(new Date()));
}
});
/*
输出:
start time:23:01:30
1.onNext:0->time:23:01:31
1.onNext:1->time:23:01:32
2.onNext:1->time:23:01:32
1.onNext:2->time:23:01:33
2.onNext:2->time:23:01:33
1.onNext:3->time:23:01:34
2.onNext:3->time:23:01:34
1.onNext:4->time:23:01:35
2.onNext:4->time:23:01:35
1.onCompleted
2.onCompleted
*/
2. Connect
connect是ConnectableObservable接口的一个方法,它的作用就是让ConnectableObservable开始发射数据(即使没有任何订阅者订阅这个Observable,调用connect都会开始发射数据)。
connect方法返回一个Subscription对象,可以调用它的unsubscribe方法让Observable停止发射数据给观察者。
示例代码:
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
Observable<Long> obs = Observable.interval(1, TimeUnit.SECONDS);
//使用publish操作符将普通Observable转换为可连接的Observable
ConnectableObservable<Long> connectableObservable = obs.publish();
//开始发射数据
Subscription sub = connectableObservable.connect();
//第二个订阅者延迟2s订阅,这将导致丢失前面2s内发射的数据
connectableObservable
.delaySubscription(3, TimeUnit.SECONDS)
.subscribe(new Subscriber<Long>() {
@Override
public void onCompleted() {
Log.v(TAG, "onCompleted");
}
@Override
public void onError(Throwable e) {
Log.v(TAG, "onError");
}
@Override
public void onNext(Long along) {
Log.v(TAG, "onNext:"+along+"->time:"+ sdf.format(new Date()));
}
});
new Timer().schedule(new TimerTask() {
@Override
public void run() {
//6s之后停止发射数据
sub.unsubscribe();
}
},6000);
/*
输出:
onNext:3->time:23:10:49
onNext:4->time:23:10:50
onNext:5->time:23:10:51
*/
3. RefCount
RefCount操作符可以看做是Publish的逆向,它能将一个ConnectableObservable对象再重新转化为一个普通的Observable对象,如果转化后有订阅者对其进行订阅将会开始发射数据,后面如果有其他订阅者订阅,将只能接受后面的数据(这也是转化之后的Observable 与普通的Observable的一点区别 )。
还有一个操作符叫share,它的作用等价于对一个Observable同时应用publish和refCount操作。
示例代码:
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
Observable<Long> obs = Observable.interval(1, TimeUnit.SECONDS).take(4);
//使用publish操作符将普通Observable转换为可连接的Observable
ConnectableObservable<Long> connectableObservable = obs.publish();
//refCount:将ConnectableObservable转化为普通Observable
Observable obsRefCount = connectableObservable.refCount();
obs.subscribe(new Subscriber<Long>() {
@Override
public void onCompleted() {
Log.v(TAG, "普通obs1:onCompleted");
}
@Override
public void onError(Throwable e) {
Log.v(TAG, "普通obs1:onError");
}
@Override
public void onNext(Long along) {
Log.v(TAG, "普通obs1:onNext:"+along+"->time:"+ sdf.format(new Date()));
}
});
obs.delaySubscription(3, TimeUnit.SECONDS)
.subscribe(new Subscriber<Long>() {
@Override
public void onCompleted() {
Log.v(TAG, "普通obs2:onCompleted");
}
@Override
public void onError(Throwable e) {
Log.v(TAG, "普通obs2:onError");
}
@Override
public void onNext(Long along) {
Log.v(TAG, "普通obs2:onNext:"+along+"->time:"+ sdf.format(new Date()));
}
});
obsRefCount.subscribe(new Subscriber<Long>() {
@Override
public void onCompleted() {
Log.v(TAG, "obsRefCount1:onCompleted");
}
@Override
public void onError(Throwable e) {
Log.v(TAG, "obsRefCount1:onError");
}
@Override
public void onNext(Long along) {
Log.v(TAG, "obsRefCount1:onNext:"+along+"->time:"+ sdf.format(new Date()));
}
});
obsRefCount.delaySubscription(3, TimeUnit.SECONDS)
.subscribe(new Subscriber<Long>() {
@Override
public void onCompleted() {
Log.v(TAG, "obsRefCount2:onCompleted");
}
@Override
public void onError(Throwable e) {
Log.v(TAG, "obsRefCount2:onError");
}
@Override
public void onNext(Long along) {
Log.v(TAG, "obsRefCount2:onNext:"+along+"->time:"+ sdf.format(new Date()));
}
});
/*
输出:
普通obs1:onNext:0->time:23:28:28
普通obs1:onNext:1->time:23:28:29
普通obs1:onNext:2->time:23:28:30
普通obs1:onNext:3->time:23:28:31
普通obs1:onCompleted
普通obs2:onNext:0->time:23:28:31
普通obs2:onNext:1->time:23:28:32
普通obs2:onNext:2->time:23:28:33
普通obs2:onNext:3->time:23:28:34
普通obs2:onCompleted
obsRefCount1:onNext:0->time:23:28:28
obsRefCount1:onNext:1->time:23:28:29
obsRefCount1:onNext:2->time:23:28:30
obsRefCount1:onNext:3->time:23:28:31
obsRefCount1:onCompleted
obsRefCount2:onNext:3->time:23:28:31
obsRefCount2:onCompleted
*/
4. Replay
通过上面的介绍我们了解到,ConnectableObservable和普通的Observable最大的区别就是,调用Connect操作符开始发射数据,后面的订阅者会丢失之前发射过的数据。
使用Replay操作符返回的ConnectableObservable 会缓存订阅者订阅之前已经发射的数据,这样即使有订阅者在其发射数据开始之后进行订阅也能收到之前发射过的数据。Replay操作符能指定缓存的大小或者时间,这样能避免耗费太多内存。
示例代码:
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
Log.v(TAG, "start time:" + sdf.format(new Date()));
//没有缓存的情况
ConnectableObservable<Long> obs = Observable.interval(1, TimeUnit.SECONDS)
.take(5)
.publish();
obs.connect(); //开始发射数据
obs.delaySubscription(3, TimeUnit.SECONDS)
.subscribe(aLong -> Log.v(TAG, "onNext:"+aLong+"->time:"+ sdf.format(new Date())));
//缓存一个数据
ConnectableObservable<Long> obs1 = Observable.interval(1, TimeUnit.SECONDS)
.take(5)
.replay(1); //缓存1个数据
obs1.connect(); //开始发射数据
obs1.delaySubscription(3, TimeUnit.SECONDS)
.subscribe(aLong -> Log.v(TAG,
"1.onNext:"+aLong+"->time:"+ sdf.format(new Date())));
//缓存3s内发射的数据
ConnectableObservable<Long> obs2 = Observable.interval(1, TimeUnit.SECONDS)
.take(5)
.replay(3, TimeUnit.SECONDS); //缓存3s
obs2.connect(); //开始发射数据
obs2.delaySubscription(3, TimeUnit.SECONDS)
.subscribe(aLong -> Log.v(TAG,
"2.onNext:"+aLong+"->time:"+ sdf.format(new Date())));
/*
输出:
start time:14:25:51
onNext:3->time:14:25:55
onNext:4->time:14:25:56
1.onNext:2->time:14:25:54
1.onNext:3->time:14:25:55
1.onNext:4->time:14:25:56
2.onNext:0->time:14:25:54
2.onNext:1->time:14:25:54
2.onNext:2->time:14:25:54
2.onNext:3->time:14:25:55
2.onNext:4->time:14:25:56
*/
从log可以看出,没有缓存机制的只能收到3.4;缓存1个数据的能收到前面已经发射过的2;缓存3s的将所有已经发射的数据都缓存起来了,所以数据都能收到。缓存的数据在订阅者订阅之后立马发射给订阅者。
源码下载:
RxJava操作符(09-算术/聚合操作&连接操作)的更多相关文章
- RxJava操作符实践:8_算术和聚合操作之3_min
发射原始Observable的最小值. Min操作符操作一个发射数值的Observable并发射单个值:最小的那个值. RxJava中,min属于rxjava-math模块. min接受一个可选参数, ...
- Update(Stage4):sparksql:第3节 Dataset (DataFrame) 的基础操作 & 第4节 SparkSQL_聚合操作_连接操作
8. Dataset (DataFrame) 的基础操作 8.1. 有类型操作 8.2. 无类型转换 8.5. Column 对象 9. 缺失值处理 10. 聚合 11. 连接 8. Dataset ...
- SQL 经典回顾:JOIN 表连接操作不完全指南
2017-02-23 小峰 ITPUB 点击上方“蓝字”可以关注我们哦  |转载自:码农网 |原文链接:www.codeceo.com/article/sql-join-guide.html ...
- MySQL 子查询与连接操作笔记
SQL语句之间是可以进行连接操作的,在一些复杂的数据操作中必须用到连接操作.简单的说就是一个SQL语句的结果可以作为相连接的SQL操作的一部分.SQL结构化查询语句,子查询是指的所有的SQL操作,并非 ...
- hbase连接操作
hbase连接操作 package com.test; import java.io.IOException; import org.apache.hadoop.conf.Configuration; ...
- php大力力 [024节]PHP中的字符串连接操作(2015-08-27)
2015-08-27 php大力力024.PHP中的字符串连接操作 PHP中的字符串连接操作 阅读:次 时间:2012-03-25 PHP字符串的连接的简单实例 时间:2013-12-30 很多 ...
- python 连接操作数据库(二)
一.我们接着上期的博客继续对ORM框架进行补充,顺便把paramiko模块也给大家讲解一下: 1.ORM框架: 在连接操作数据库的第一个博客中也已经说了,sqlalchemy是一个ORM框架,总结就是 ...
- python 连接操作数据库(一)
一.下面我们所说的就是连接mysql的应用: 1.其实在python中连接操作mysql的模块有多个,在这里我只给大家演示pymysql这一个模块(其实我是感觉它比较好用而已): pymysql是第三 ...
- 关闭数据库下的所有连接操作 sql存储过程
use master go )) as begin ),) declare @spid int set @sql='declare getspid cursor for select spid fro ...
随机推荐
- 在windows系统之中查看目前已安装的更新
方法1:使用PowerShell get-hotfix 方法2:使用cmd systeminfo.exe 参考链接
- 聊聊Servlet、Struts1、Struts2以及SpringMvc中的线程安全
前言 很多初学者,甚至是工作1-3年的小伙伴们都可能弄不明白?servlet Struts1 Struts2 springmvc 哪些是单例,哪些是多例,哪些是线程安全? 在谈这个话题之前,我们先了解 ...
- Android基础字符串String.md
问题抛出 String这个常量在我们代码中会经常被用到,那么我们了解 String stringbuffer StringBudilder三者之间的区别吗 问题解答 String 字符串常量,位于常量 ...
- C#之读写压缩文件
在处理文件时,常常会发现文件中有许多空格,耗尽了硬盘空间,.net的类提供了GZIP/Deflate算法可以压缩文件.这里只介绍了文件的压缩,但在实际应用更多的是压缩文件夹 压缩文件 解压文件 可以使 ...
- 一篇文章说透Nginx的rewrite模块
rewrite模块即ngx_http_rewrite_module模块,主要功能是改写请求URI,是Nginx默认安装的模块.rewrite模块会根据PCRE正则匹配重写URI,然后发起内部跳转再匹配 ...
- 如何降低移动APP的开发成本
在当下竞争激烈的商业世界中,移动APP开发是您业务的有利补充.移动APP可通过吸引新客户和保留现有客户,帮助公司成功开展业务.定制一个属于自己公司的移动APP扮演着重要角色,手机APP可以说通过轻松处 ...
- java--- 使用interrupte中断线程的真正用途
Java线程之中,一个线程的生命周期分为:初始.就绪.运行.阻塞以及结束.当然,其中也可以有四种状态,初始.就绪.运行以及结束. 一般而言,可能有三种原因引起阻塞:等待阻塞.同步阻塞以及其他阻塞(睡眠 ...
- [LeetCode] Brick Wall 砖头墙壁
There is a brick wall in front of you. The wall is rectangular and has several rows of bricks. The b ...
- hadoop一键安装伪分布式
hadoop伪分布式和hive在openSUSE中的安装 在git上的路径为:https://github.com/huabingood/hadoop--------/tree/master 各个文件 ...
- shell编程-项目部署(优化篇)
在实际工作中小编遇到了一个问题那就是当我去操作部署脚本的时候,另一个人也可以操作,这怎么能行啊,后来小编就觉得重新优化下代码,给它加一个进程锁 老规矩,先梳理下思路: 同一时间内,脚本只能够允许一个人 ...