Rx java 立即交付第一项&x27;去盎司';下列项目

Rx java 立即交付第一项&x27;去盎司';下列项目,rx-java,rx-android,Rx Java,Rx Android,考虑以下用例: 需要尽快交付第一件物品 需要以1秒超时消除以下事件的抖动 我最终实现了基于操作符或随时间变化的自定义操作符,然后像这样使用它 .lift(new CustomOperatorDebounceWithTime<>(1, TimeUnit.SECONDS, Schedulers.computation())) .lift(新的自定义运算符debouncwithtime(1,TimeUnit.SECONDS,Schedulers.computation()) Cus

考虑以下用例:

  • 需要尽快交付第一件物品
  • 需要以1秒超时消除以下事件的抖动
我最终实现了基于
操作符或随时间变化的自定义操作符,然后像这样使用它

.lift(new CustomOperatorDebounceWithTime<>(1, TimeUnit.SECONDS, Schedulers.computation()))
.lift(新的自定义运算符debouncwithtime(1,TimeUnit.SECONDS,Schedulers.computation())
CustomOperatorDebounceWithTime
立即交付第一个项目,然后使用
OperatorDebounceWithTime
操作员的逻辑对后续项目进行取消装箱

有没有更简单的方法来实现所描述的行为?让我们跳过
compose
操作符,它不能解决问题。我正在寻找一种在不实现自定义运算符的情况下实现这一点的方法。

更新:
根据@lopar的评论,更好的方法是:

Observable.from(items).publish(publishedItems -> publishedItems.limit(1).concatWith(publishedItems.skip(1).debounce(1, TimeUnit.SECONDS)))
你喜欢这项工作吗

String[] items = {"one", "two", "three", "four", "five", "six", "seven", "eight"};
Observable<String> myObservable = Observable.from(items);
Observable.concat(myObservable.first(), myObservable.skip(1).debounce(1, TimeUnit.SECONDS))
    .subscribe(s -> System.out.println(s));
String[]items={“一”、“二”、“三”、“四”、“五”、“六”、“七”、“八”};
可观测的myObservable=可观测的(项目);
concat(myObservable.first(),myObservable.skip(1).去盎司(1,时间单位.秒))
.订阅->系统输出打印项次;

由@LortRaydenMK和@lopar给出的答案是最好的,但我想提出一些其他建议,以防它碰巧对您或处于类似情况的人更有效

有一个
debounce()
的变体,它使用一个函数来决定对该特定项进行多长时间的去抖动。它通过返回一个在一段时间后完成的可观察对象来指定这一点。您的函数可以为第一项返回
empty()
,为其余项返回
timer()
。类似于(未经测试):


诀窍是这个函数必须知道哪个项是第一项。你的序列可能知道这一点。如果没有,您可能必须使用
range()
或其他方法来
zip()
。在这种情况下,最好在另一个答案中使用该解决方案。

一个使用RxJava 2.0的简单解决方案,翻译自,它结合了throttleFirst和debounce,然后删除重复项

private observectransformer debounceImmediate(){
返回可观察->可观察.发布(p->
可观察。合并(p.throttleFirst(1,时间单位。秒),
p、 去盎司(1,时间单位为秒)).distinctunitrichanged();
} 
@试验
公共无效测试DeBounceimmediate(){
可观察的。刚好(0,100,200,1500,1600,1800,2000,10000)
.flatMap(v->Observable.timer(v,TimeUnit.millides).map(w->v))
.doOnNext(v->System.out.println(LocalDateTime.now()+“T=“+v))
.compose(debounceImmediate())
.blockingSubscribe(v->System.out.println(LocalDateTime.now()+“取消公告:”+v));
}

使用limit()或take()的方法似乎无法处理长寿命的数据流,我可能希望不断观察这些数据流,但对于第一个看到的事件,仍然会立即采取行动。

使用采用函数的
debounce
版本,并以以下方式实现该函数:

    .debounce(new Func1<String, Observable<String>>() {
        private AtomicBoolean isFirstEmission = new AtomicBoolean(true);
        @Override
        public Observable<String> call(String s) {
             // note: standard debounce causes the first item to be
             // delayed by 1 second unnecessarily, this is a workaround
             if (isFirstEmission.getAndSet(false)) {
                 return Observable.just(s);
             } else {
                 return Observable.just(s).delay(1, TimeUnit.SECONDS);
             }
        }
    })
.debounce(新函数1(){
私有AtomicBoolean isFirstEmission=新的AtomicBoolean(true);
@凌驾
公共可观察调用(字符串s){
//注:标准去盎司会导致第一项
//不必要地延迟1秒,这是一种解决方法
if(isFirstEmission.getAndSet(false)){
可观察到的回报。仅(s);
}否则{
返回可观察的延迟(1,时间单位秒);
}
}
})
第一项立即发射。后续项目将延迟一秒钟。如果延迟的可观测项没有在以下项目到达之前终止,它将被取消,从而实现预期的去盎司行为。

有一个问题:您总是丢失第二个项目。我感到惊讶的是,以前没有人意识到这一点,因为如果你有一个去盎司,你通常有很多事件,第二个是讨论去盎司无论如何。避免丢失事件的正确方法是:

observable
    .publish(published ->
        published
            .limit(1)
            .concatWith(published.debounce(1, TimeUnit.SECONDS)));
别担心,你不会得到任何重复的事件。如果您对此不确定,可以运行此代码并亲自检查:

Observable.just(1, 2, 3, 4)
    .publish(published ->
        published
            .limit(1)
            .concatWith(published))
    .subscribe(System.out::println);

Ngrx-rxjs解决方案,将管道分成两部分

onMyAction$ = this.actions$
    .pipe(ofType<any>(ActionTypes.MY_ACTION);

lastTime = new Date();

@Effect()
onMyActionWithAbort$ = this.onMyAction$
    .pipe(
        filter((data) => { 
          const result = new Date() - this.lastTime > 200; 
          this.lastTime = new Date(); 
          return result; 
        }),
        switchMap(this.DoTheJob.bind(this))
    );

@Effect()
onMyActionWithDebounce$ = this.onMyAction$
    .pipe(
        debounceTime(200),
        filter(this.preventDuplicateFilter.bind(this)),
        switchMap(this.DoTheJob.bind(this))
    );
onMyAction$=this.actions$
.pipe(of类型(ActionTypes.MY_ACTION);
lastTime=新日期();
@效果()
onMyActionWithAbort$=this.onMyAction$
.烟斗(
过滤器((数据)=>{
const result=new Date()-this.lastTime>200;
this.lastTime=新日期();
返回结果;
}),
switchMap(this.DoTheJob.bind(this))
);
@效果()
onMyActionWithDebounce$=此.onMyAction$
.烟斗(
去BounceTime(200),
筛选器(this.preventDuplicateFilter.bind(this)),
switchMap(this.DoTheJob.bind(this))
);

基于@lopar评论的Kotlin扩展函数:

fun Flowable.debounceImmediate(超时:长,单位:TimeUnit):可流动{
返回发布{
it.take(1.concatWith(it.debounce(超时,单位))
}
}
有趣的可观察到。去Bounceimmediate(超时:长,单位:TimeUnit):可观察到{
返回发布{
it.take(1.concatWith(it.debounce(超时,单位))
}
}

防止双重订阅 使用此选项:

    const debouncedSkipFirstStream$ = stream$.pipe(
        map((it, index) => ({ it, index })),
        debounce(({ index }) => (
            index ? new Promise(res => setTimeout(res, TimeUnit.SECONDS))
                : Rx.of(true))),
        map(({ it }) => it),
    );
如果使用拆分解决方案,您将看到“运行”打印两次

x = rxjs.Observable.create(o=>{
    console.info('run');
    o.next(1);
    o.next(2);
});
a = x.pipe(rxjs.operators.take(1));
b = x.pipe(rxjs.operators.skip(1), rxjs.operators.debounceTime(60));
rxjs.concat(a, b).subscribe(console.log);
我的Dart解决方案:

extension StreamExt<T> on Stream<T> {
  Stream<T> immediateDebounce(Duration duration) {
    var lastEmit = 0;
    return debounce((event) {
      if (_now - lastEmit < duration.inMilliseconds) {
        lastEmit = _now;
        return Stream.value(event).delay(duration);
      } else {
        lastEmit = _now;
        return Stream.value(event);
      }
    });
  }
}

int get _now =>  DateTime.now().millisecondsSinceEpoch;
流上的扩展流文本{
流立即反弹(持续时间){
var lastEmit=0;
返回去盎司((事件){
if(_now-lastEmitDateTime.now();
我和

Flowable.concat(

    flowable // emits immediately
        .take(1)
        .skipWhile { it.isEmpty() },

    flowable // same flowable, but emits with delay and debounce
        .debounce(2, TimeUnit.SECONDS)
)
    .distinctUntilChanged()

您还可以防止进行双重订阅(在
Flowable.concat(

    flowable // emits immediately
        .take(1)
        .skipWhile { it.isEmpty() },

    flowable // same flowable, but emits with delay and debounce
        .debounce(2, TimeUnit.SECONDS)
)
    .distinctUntilChanged()