RxJava操作符(三)Filtering_PHP教程
RxJava操作符(三)Filtering
在上一篇文章里,我们了解了转化操作符,能将数据转化为我们想要的格式,但是如果数据集合里面有一些我们想要过滤掉的数据怎么办?这时候我们就需要使用过滤操作符了,有点类似于sql里的where,让Observable只返回满足我们条件的数据。一、debounce
debounce操作符就是起到了限流的作用,可以理解为阀门,当你半开阀门的时候,水会以较慢的速度流出来。不同之处就是阀门里的水不会浪费掉,而debounce过滤掉的数据会被丢弃掉。在Rxjava中,将这个操作符氛围了
throttleWithTimeout
和debounce两个操作符。先来看一下throttleWithTimeOut吧,如下图所示,这个操作符通过时间来限流,源Observable每次发射出来一个数据后就会进行计时,如果在设定好的时间结束前源Observable有新的数据发射出来,这个数据就会被丢弃,同时重新开始计时。如果每次都是在计时结束前发射数据,那么这个限流就会走向极端:只会发射最后一个数据。<br><img src="/static/imghw/default1.png" data-src="http://www.bkjia.com/uploads/allimg/151205/1151453N3-0.png" class="lazy" style="max-width:90%" style="max-width:90%" alt=""><br><br> 首先我们来创建一个Observable,每隔100毫秒发射一个数据,当要发射的数据是3的倍数的时候,下一个数据就延迟到300毫秒再发射。<br><br><p></p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'><ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>private Observable<Integer> createObserver() {<br /></li><li>return Observable.create(new Observable.OnSubscribe<Integer>() {<br /></li><li>@Override<br /></li><li>public void call(Subscriber<? super Integer> subscriber) {<br /></li><li>for (int i = 0; i < 10; i++) {<br /></li><li>if (!subscriber.isUnsubscribed()) {<br /></li><li>subscriber.onNext(i);<br /></li><li>}<br /></li><li>int sleep = 100;<br /></li><li>if (i % 3 == 0) {<br /></li><li>sleep = 300;<br /></li><li>}<br /></li><li>try {<br /></li><li>Thread.sleep(sleep);<br /></li><li>} catch (InterruptedException e) {<br /></li><li>e.printStackTrace();<br /></li><li>}<br /></li><li><br /></li><li>}<br /></li><li>subscriber.onCompleted();<br /></li><li>}<br /></li><li>}).subscribeOn(Schedulers.computation());<br /></li><li>}</li></ol></pre><div class="contentsignin">登录后复制</div></div> 下面使用throttleWithTimeOut来过滤一下这个Observable,我们设定的过滤时间是200毫秒,也就说发射间隔小于200毫秒的数据会被过滤掉。<br /><br /><p></p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'><ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>private Observable<Integer> throttleWithTimeoutObserver() {<br /></li><li>return createObserver().throttleWithTimeout(200, TimeUnit.MILLISECONDS)<br /></li><li>.observeOn(AndroidSchedulers.mainThread());<br /></li><li><br /></li><li>}</li></ol></pre><div class="contentsignin">登录后复制</div></div> 对其进行订阅<br /><br /><p></p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'><ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>mLButton.setText("throttleWithTimeout");<br /></li><li>mLButton.setOnClickListener(e -> throttleWithTimeoutObserver().subscribe(i -> log("throttleWithTimeout:" + i)));</li></ol></pre><div class="contentsignin">登录后复制</div></div> 运行结果如下,可以看到,不是3的倍数的数据在发射后200毫秒内会发射出新的数据,所以会被过滤掉。<br /><img src="/static/imghw/default1.png" data-src="http://www.bkjia.com/uploads/allimg/151205/1151453122-1.png" class="lazy" style="max-width:90%" style="max-width:90%" alt="" /><br /> debounce操作符也可以使用时间来进行过滤,这时它跟throttleWithTimeOut使用起来是一样,但是deounce操作符还可以根据一个函数来进行限流。这个函数的返回值是一个临时Observable,如果源Observable在发射一个新的数据的时候,上一个数据根据函数所生成的临时Observable还没有结束,那么上一个数据就会被过滤掉。<br /><img src="/static/imghw/default1.png" data-src="http://www.bkjia.com/uploads/allimg/151205/115145L93-2.png" class="lazy" style="max-width:90%" style="max-width:90%" alt="" /><br /> 生成一个Observable并使用debounce对其进行过滤,只有发射来的数据为偶数的时候才会调用onCompleted方法来表示这个临时的Observable已经终止。<br /><br /><p></p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'><ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>private Observable<Integer> debounceObserver() {<br /></li><li>return Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9).debounce(integer -> {<br /></li><li>log(integer);<br /></li><li>return Observable.create(new Observable.OnSubscribe<Integer>() {<br /></li><li>@Override<br /></li><li>public void call(Subscriber<? super Integer> subscriber) {<br /></li><li>if (integer % 2 == 0 && !subscriber.isUnsubscribed()) {<br /></li><li>log("complete:" + integer);<br /></li><li>subscriber.onNext(integer);<br /></li><li>subscriber.onCompleted();<br /></li><li>}<br /></li><li>}<br /></li><li>});<br /></li><li>})<br /></li><li>.observeOn(AndroidSchedulers.mainThread());<br /></li><li>}</li></ol></pre><div class="contentsignin">登录后复制</div></div> 对其进行订阅<br /><br /><p></p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'><ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>mRButton.setOnClickListener(e -> debounceObserver().subscribe(i -> log("debounce:" + i)));</li></ol></pre><div class="contentsignin">登录后复制</div></div> 运行结果如下,可以看到,只有那些调用了onCompleted方法的数据才会被发射出来,其他的都过滤掉了。<br /><img src="/static/imghw/default1.png" data-src="http://www.bkjia.com/uploads/allimg/151205/1151451P1-3.png" class="lazy" style="max-width:90%" style="max-width:90%" alt="" /><br /><br /> 二、Distinct<br /> Distinct操作符的用处就是用来去重,非常好理解。如下图所示,所有重复的数据都会被过滤掉。还有一个操作符distinctUntilChanged,是用来过滤掉连续的重复数据。<br /><img src="/static/imghw/default1.png" data-src="http://www.bkjia.com/uploads/allimg/151205/1151452R6-4.png" class="lazy" style="max-width:90%" alt="" /><img src="/static/imghw/default1.png" data-src="http://www.bkjia.com/uploads/allimg/151205/1151455E3-5.png" class="lazy" style="max-width:90%" alt="" /><br /> 创建两个Observable,并使用Distinct和DistinctUtilChanged操作符分别对其进行过滤<br /><br /><p></p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'><ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>private Observable<Integer> distinctObserver() {<br /></li><li>return Observable.just(1, 2, 3, 4, 5, 4, 3, 2, 1).distinct();<br /></li><li><br /></li><li>}<br /></li><li><br /></li><li>private Observable<Integer> distinctUntilChangedObserver() {<br /></li><li>return Observable.just(1, 2, 3, 3, 3, 1, 2, 3, 3).distinctUntilChanged();<br /></li><li><br /></li><li>}</li></ol></pre><div class="contentsignin">登录后复制</div></div> 进行订阅<br /><br /><p></p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'><ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>mLButton.setText("distinct");<br /></li><li>mLButton.setOnClickListener(e -> distinctObserver().subscribe(i -> log("distinct:" + i)));<br /></li><li>mRButton.setText("UntilChanged");<br /></li><li>mRButton.setOnClickListener(e -> distinctUntilChangedObserver().subscribe(i -> log("UntilChanged:" + i)));</li></ol></pre><div class="contentsignin">登录后复制</div></div> 运行结果如下所示,可以看到Distinct过滤掉了所有重复的数字,二DistinctUtilChanged只过滤掉重复的数字<br /><img src="/static/imghw/default1.png" data-src="http://www.bkjia.com/uploads/allimg/151205/11514535Z-6.png" class="lazy" style="max-width:90%" style="max-width:90%" alt="" /><br /><br /> 三、ElementAt、Filter<br /> 这两个操作符都很好理解,ElementAt只会返回指定位置的数据,而Filter只会返回满足过滤条件的数据,其示意图分别如下所示<br /><img src="/static/imghw/default1.png" data-src="http://www.bkjia.com/uploads/allimg/151205/115145E34-7.png" class="lazy" style="max-width:90%" alt="" /><img src="/static/imghw/default1.png" data-src="http://www.bkjia.com/uploads/allimg/151205/1151453D1-8.png" class="lazy" style="max-width:90%" alt="" /><br /> 创建两个Observable对象并分别使用ElementAt和Filter操作符对其进行过滤<br /><br /><p></p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'><ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>private Observable<Integer> elementAtObserver() {<br /></li><li>return Observable.just(0, 1, 2, 3, 4, 5).elementAt(2);<br /></li><li>}<br /></li><li><br /></li><li>private Observable<Integer> FilterObserver() {<br /></li><li>return Observable.just(0, 1, 2, 3, 4, 5).filter(i -> i < 3);<br /></li><li>}</li></ol></pre><div class="contentsignin">登录后复制</div></div> 分别对其进行订阅<br /><br /><p></p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'><ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>mLButton.setText("elementAt");<br /></li><li>mLButton.setOnClickListener(e -> elementAtObserver().subscribe(i -> log("elementAt:" + i)));<br /></li><li>mRButton.setText("Filter");<br /></li><li>mRButton.setOnClickListener(e -> FilterObserver().subscribe(i -> log("Filter:" + i)));</li></ol></pre><div class="contentsignin">登录后复制</div></div> 运行结果如下<br /><img src="/static/imghw/default1.png" data-src="http://www.bkjia.com/uploads/allimg/151205/1151451453-9.png" class="lazy" style="max-width:90%" style="max-width:90%" alt="" /><br /><br /> 四、First、Last<br /> First操作符只会返回第一条数据,并且还可以返回满足条件的第一条数据。如果你看过我以前的博客,就会发现在我们使用Rxjava实现三级缓存的例子里,就是使用first操作符来选择所要使用的缓存。与First相反,Last操作符只返回最后一条满足条件的数据。<br /><img src="/static/imghw/default1.png" data-src="http://www.bkjia.com/uploads/allimg/151205/115145DO-10.png" class="lazy" style="max-width:90%" alt="" /><img src="/static/imghw/default1.png" data-src="http://www.bkjia.com/uploads/allimg/151205/115145L02-11.png" class="lazy" style="max-width:90%" alt="" /><br /> 另外还有一个BlockingObservable方法,这个方法不会对Observable做任何处理,只会阻塞住,当满足条件的数据发射出来的时候才会返回一个BlockingObservable对象。可以使用<code style="box-sizing:border-box;padding:2px 4px;border-radius:4px;white-space:normal;">Observable.toBlocking
或者BlockingObservable.from
方法来将一个Observable对象转化为BlockingObservable对象。BlockingObservable可以和first操作符进行配合使用。
创建两个Observable对象并分别使用first操作符进行处理
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>private Observable<Integer> FirstObserver() {<br /></li><li>return Observable.just(0, 1, 2, 3, 4, 5).first(i -> i > 1);<br /></li><li>}<br /></li><li><br /></li><li>private BlockingObservable<Integer> FilterObserver() {<br /></li><li>return Observable.create(new Observable.OnSubscribe<Integer>() {<br /></li><li>@Override<br /></li><li>public void call(Subscriber<? super Integer> subscriber) {<br /></li><li>for (int i = 0; i < 5; i++) {<br /></li><li>try {<br /></li><li>Thread.sleep(500);<br /></li><li>} catch (InterruptedException e) {<br /></li><li>e.printStackTrace();<br /></li><li>}<br /></li><li>if (!subscriber.isUnsubscribed()) {<br /></li><li>log("onNext:" + i);<br /></li><li>subscriber.onNext(i);<br /></li><li>}<br /></li><li>}<br /></li><li>if (!subscriber.isUnsubscribed()) {<br /></li><li>subscriber.onCompleted();<br /></li><li>}<br /></li><li>}<br /></li><li>}).toBlocking();<br /></li><li>}</li></ol>
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>mLButton.setText("First");<br /></li><li>mLButton.setOnClickListener(e -> FirstObserver().subscribe(i -> log("First:" + i)));<br /></li><li>mRButton.setText(" Blocking");<br /></li><li>mRButton.setOnClickListener(e -> {<br /></li><li>log("blocking:" + FilterObserver().first(i -> i > 1));<br /></li><li>});</li></ol>

五、Skip、Take
Skip操作符将源Observable发射的数据过滤掉前n项,而Take操作符则只取前n项,理解和使用起来都很容易,但是用处很大。另外还有SkipLast和TakeLast操作符,分别是从后面进行过滤操作。


创建两个Observable并分别使用skip和take操作符对其进行过滤操作
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>private Observable<Integer> skipObserver() {<br /></li><li>return Observable.just(0, 1, 2, 3, 4, 5).skip(2);<br /></li><li>}<br /></li><li>private Observable<Integer> takeObserver() {<br /></li><li>return Observable.just(0, 1, 2, 3, 4, 5).take(2);<br /></li><li>}</li></ol>
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>mLButton.setText("Skip");<br /></li><li>mLButton.setOnClickListener(e -> skipObserver().subscribe(i -> log("Skip:" + i)));<br /></li><li>mRButton.setText("Take");<br /></li><li>mRButton.setOnClickListener(e -> takeObserver().subscribe(i -> log("Take:" + i)));</li></ol>

六、Sample、ThrottleFirst
Sample操作符会定时地发射源Observable最近发射的数据,其他的都会被过滤掉,等效于ThrottleLast操作符,而ThrottleFirst操作符则会定期发射这个时间段里源Observable发射的第一个数据


我们创建一个Observable每隔200毫秒发射一个数据,然后分别使用sample和throttleFirst操作符对其进行过滤
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>private Observable<Integer> sampleObserver() {<br /></li><li>return createObserver().sample(1000, TimeUnit.MILLISECONDS);<br /></li><li>}<br /></li><li><br /></li><li>private Observable<Integer> throttleFirstObserver() {<br /></li><li>return createObserver().throttleFirst(1000, TimeUnit.MILLISECONDS);<br /></li><li>}<br /></li><li><br /></li><li><br /></li><li>private Observable<Integer> createObserver() {<br /></li><li>return Observable.create(new Observable.OnSubscribe<Integer>() {<br /></li><li>@Override<br /></li><li>public void call(Subscriber<? super Integer> subscriber) {<br /></li><li>for (int i = 0; i < 20; i++) {<br /></li><li>try {<br /></li><li>Thread.sleep(200);<br /></li><li>} catch (InterruptedException e) {<br /></li><li>e.printStackTrace();<br /></li><li>}<br /></li><li>subscriber.onNext(i);<br /></li><li>}<br /></li><li>subscriber.onCompleted();<br /></li><li>}<br /></li><li>});<br /></li><li>}</li></ol>
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>mLButton.setText("sample");<br /></li><li>mLButton.setOnClickListener(e -> sampleObserver().subscribe(i -> log("sample:" + i)));<br /></li><li>mRButton.setText("throttleFirst");<br /></li><li>mRButton.setOnClickListener(e -> throttleFirstObserver().subscribe(i -> log("throttleFirst:" + i)));</li></ol>

本文的demo程序见github:https://github.com/Chaoba/RxJavaDemo

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

最近几天,Ice Universe 不断披露有关 Galaxy S25 Ultra 的详细信息,人们普遍认为这款手机将是三星的下一款旗舰智能手机。除此之外,泄密者声称三星只计划升级一款相机

OnLeaks 现在与 Android Headlines 合作,首次展示了 Galaxy S25 Ultra,几天前,他试图从他的 X(以前的 Twitter)粉丝那里筹集到 4,000 美元以上的资金,但失败了。对于上下文,嵌入在 h 下面的渲染图像

除了发布两款新智能手机外,TCL 还发布了一款名为 NXTPAPER 14 的新 Android 平板电脑,其大屏幕尺寸是其卖点之一。 NXTPAPER 14 采用 TCL 标志性品牌哑光液晶面板 3.0 版本

最近几天,Ice Universe 不断披露有关 Galaxy S25 Ultra 的详细信息,人们普遍认为这款手机将是三星的下一款旗舰智能手机。除此之外,泄密者声称三星只计划升级一款相机

Vivo Y300 Pro刚刚全面亮相,它是最薄的中端Android手机之一,配备大电池。准确来说,这款智能手机的厚度仅为 7.69 毫米,但配备了 6,500 mAh 的电池。这与最近推出的容量相同

三星尚未就何时更新其 Fan Edition (FE) 智能手机系列提供任何提示。目前来看,Galaxy S23 FE 仍然是该公司的最新版本,于 2023 年 10 月年初推出。

Redmi Note 14 Pro Plus 现已正式成为去年 Redmi Note 13 Pro Plus 的直接后继产品(亚马逊售价 375 美元)。正如预期的那样,Redmi Note 14 Pro Plus与Redmi Note 14和Redmi Note 14 Pro一起成为Redmi Note 14系列的主角。李

摩托罗拉今年发布了无数设备,尽管其中只有两款是可折叠的。就上下文而言,虽然世界上大多数地区都收到了 Razr 50 和 Razr 50 Ultra,但摩托罗拉在北美提供了 Razr 2024 和 Razr 2
