简体   繁体   English

rxjava delay:如何从列表中发出的每个项目获得可变延迟?

[英]rxjava delay: How to get variable delay on each item emitted from a list?

I want to have custom delays between each item emitted from an observable list as a function of the items themselves. 我希望从可观察列表中发出的每个项目之间的自定义延迟作为项目本身的函数。 Let's say we have a list as (item, delay): 假设我们有一个列表(项目,延迟):

[("item1", 2),("item2", 1),("item3", 2),("item4", 3),("item5", 2),("item6", 3)]

I want output to be something like: 我希望输出类似于:

0 seconds: 
1 seconds: 
item1
2 seconds: 
item2
3 seconds: 
4 seconds: 
item3
5 seconds: 
6 seconds: 
7 seconds: 
item4
8 seconds: 
9 seconds: 
item5
10 seconds: 
11 seconds: 
12 seconds: 
item6
Completed!
13 seconds: 

I am not sure how to best accomplish this with delay/timer operators. 我不知道如何通过延迟/计时器操作员来最好地完成此操作。 Went through delay documentation but couldn't figure out a straightforward way. 通过延迟文档,但无法找到一个简单的方法。 Any pointers would be helpful. 任何指针都会有所帮助。 Thanks! 谢谢!

No need for anything fancy. 不需要任何花哨的东西。 Just use concatMap and delay operators 只需使用concatMapdelay运算符

jla.concatMap(s -> Observable.just(s).delay(s.delay, TimeUnit.SECONDS))           
  .subscribe(s1 -> System.out.println(s1.name + " just came..."), 
             e -> {}, 
             () -> System.out.println("Everybody came!")); 

You may try to use this override of .delay() http://reactivex.io/RxJava/javadoc/rx/Observable.html#delay(rx.functions.Func1) 您可以尝试使用.delay() http://reactivex.io/RxJava/javadoc/rx/Observable.html#delay (rx.functions.Func1)的覆盖

It seems exactly what you need 这似乎正是你所需要的

The code would be something like: 代码如下:

yourObservable.delay((item) -> Observable.timer(item.getDelay(), TimeUnit.SECONDS))

I might have a possible solution as below. 我可能有一个可能的解决方案如下。 Though I feel like there can be a better way to implement it, but this works for now. 虽然我觉得可以有更好的方法来实现它,但现在这种方法很有用。 Do suggest alternatives/improvements if you see ways to make this better: 如果您想方设法做到这一点,请建议替代/改进:

import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import rx.Observable;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Func1;

public class Watchtower {
    public static void main(String[] arg) throws Exception {

        // Boilerplate for setup
        System.out.println("Welcome to Watchtower");

        class SuperHero {
            public String name;
            public long delay;

            public SuperHero(String name, int delay) {
                this.name = name;
                this.delay = (long) delay;
            }
        }

        Observable<Long> clock = Observable.interval(1, TimeUnit.SECONDS).take(14);

        clock.subscribe(tick -> System.out.println(tick + " seconds: "));

        List<SuperHero> jla = new ArrayList<>(Arrays.asList(
            new SuperHero("Bruce", 2),
            new SuperHero("Barry", 1),
            new SuperHero("Clark", 2),
            new SuperHero("Hal", 3),
            new SuperHero("Arthur", 2),
            new SuperHero("Diana", 3)
            )
        );

        // Rxjava stuff starts form here:

        Observable<SuperHero> jl = Observable.from(jla);

        final long[] cumDelay = {0};

        Observable<SuperHero> delays = jl
            .doOnNext(s -> cumDelay[0] += s.delay)
            .delay(s -> Observable.timer(cumDelay[0], TimeUnit.SECONDS));

        Observable.zip(jl, delays, (s, d) -> s)
            .doOnNext(s -> System.out.println(s.name + " just came..."))
            .doOnCompleted(() -> System.out.println("Everybody came!"))
            .subscribe();

        // Just to have program remain alive and run on normal command line
        Thread.sleep(15000);
    }
}

The output it produces: 它产生的输出:

Welcome to Watchtower
0 seconds: 
1 seconds: 
Bruce just came...
2 seconds: 
Barry just came...
3 seconds: 
4 seconds: 
Clark just came...
5 seconds: 
6 seconds: 
7 seconds: 
Hal just came...
8 seconds: 
9 seconds: 
Arthur just came...
10 seconds: 
11 seconds: 
12 seconds: 
Diana just came...
Everybody came!
13 seconds: 

In order to delay a particular step you can use zip and combine that every item emitted in your first Observable.from go with an interval of X time. 为了延迟特定步骤,您可以使用zip并将第一个Observable.from中发出的每个项目与X时间间隔相结合。

/**
 * If we want to delay the every single item emitted in the pipeline we will need a hack,
 * one possible hack is use zip operator and combine every item emitted with an interval so every item emitted has to wait until interval emit the item.
   */
   @Test
   public void delay() {
       long start = System.currentTimeMillis();
       Subscription subscription = Observable.zip(Observable.from(Arrays.asList(1, 2, 3)), Observable.interval(200, TimeUnit.MILLISECONDS), (i, t) -> i)
                                      .subscribe(n ->System.out.println("time:" + (System.currentTimeMillis() - start)));
           new TestSubscriber((Observer) subscription).awaitTerminalEvent(3000, TimeUnit.MILLISECONDS);
       }

This will print 这将打印

          time:537
          time:738
          time:936

More practicle examples here https://github.com/politrons/reactive 更多实例示例https://github.com/politrons/reactive

You can also make user of Timer operator Have a look at this 您也可以让Timer操作员的用户看看这个

Integer[] arr = {1, 2, 3, 4, 5, 6, 7};
Observable.fromArray(arr)
        // timer returns a 0 value, note the nested map operator usage
        // in order to preserve original integers
        .flatMap(x -> Observable.timer(50 * x, TimeUnit.MILLISECONDS)
                    .map(y -> x))
        .timestamp()
        .subscribe(timedIntegers ->
                Log.i(TAG, "Timed String: "
                        + timedIntegers.value()
                        + " "
                        + timedIntegers.time()));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM