RxJava运算符类似于replay(1、1,MINUTE),但在经过1分钟后会重新订阅

时间:2019-09-26 18:30:24

标签: android kotlin rx-java reactive-programming rx-java2

我需要一种相对简单的缓存过期机制(例如1分钟)。

  1. 第一个订阅者订阅时,我要进行API调用。
  2. 第二个人在几分钟之内订阅时,不希望进行API调用,而是向下游推送先前加载的值。
  3. 当第一个订阅者在一分钟后订阅时,我希望再次进行API调用。

现在,我想在单个rxjava链中执行此操作。 .replay(1, 1, MINUTE)看起来很完美,直到我了解到,经过一分钟之后,可观察的源不再被订阅。我再也看不到任何东西了。我可能需要将replay()repeatWhen{}合并但无法完全找到的东西。我尝试了非常奇特的组合,但没有一个适合我的测试用例。

3 个答案:

答案 0 :(得分:3)

这可能不是最好的解决方案,但我会尝试通过这种方式做到这一点:

    public final class SimpleCacheSingle<T : Any> constructor(
     val apiRequest: (value: String, callback: (T) -> Unit) -> Unit
 ) {
     private var lastTimeSeconds = 0L
     private lateinit var cachedValue: T

     fun getSingle(): Single<T> = Single.create { emitter ->
         if (System.currentTimeMillis() / 1000 - lastTimeSeconds > 60) {
             apiRequest("example argument") {
                 cachedValue = it
                 lastTimeSeconds = System.currentTimeMillis() / 1000
                 emitter.onSuccess(cachedValue)
             }
         } else {
             emitter.onSuccess(cachedValue)
         }
     }
 }

只需创建它的一个实例,然后使用getSingle()为每个订户创建一个。

附带的代码段中的“ apiRequest”当然需要进行修改以满足您的需求。

编辑: 请注意,如果在上一个api调用完成之前进行订阅,则将有两个或多个待处理的API请求,而不是一个。 您将需要修改代码,以便一次只请求一个。

答案 1 :(得分:0)

我认为这段代码(时间间隔是5秒而不是1分钟。测试更容易)应该可以解决问题:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss").withZone(ZoneId.systemDefault());
AtomicInteger subscriberCounter = new AtomicInteger(0);
PublishProcessor<String> repeater = PublishProcessor.create();

Flowable<String> flowable =
    Flowable.defer(() -> Flowable.just(apiCall()))
            .repeatWhen(handler -> repeater
                                     .skip(5, SECONDS) // don't trigger a repeat for any new subscription between 0 and 5 seconds
                                     .throttleFirst(5, SECONDS) // trigger a repeat and ignore any new notification during 5 sec
            )
            .replay(1)
            .autoConnect()
            .doOnSubscribe(s -> {
                System.out.println(formatter.format(now())
                                    + " -----> new subscription of subscriber #"
                                    + subscriberCounter.incrementAndGet());
                repeater.onNext("whatever"); // notify a new subscription to the repeat handler
            });

flowable.subscribe(s ->System.out.println("subscriber #1 receives: " + s));
Thread.sleep(3000);
flowable.subscribe(s -> System.out.println("subscriber #2 receives: " + s));
Thread.sleep(4000);
flowable.subscribe(s -> System.out.println("subscriber #3 receives: " + s));
Thread.sleep(100);
flowable.subscribe(s -> System.out.println("subscriber #4 receives: " + s));
Thread.sleep(6000);
flowable.subscribe(s -> System.out.println("subscriber #5 receives: " + s));
Thread.sleep(1000);
flowable.subscribe(s -> System.out.println("subscriber #6 receives: " + s));
Thread.sleep(6000);
flowable.subscribe(s -> System.out.println("subscriber #7 receives: " + s));

Flowable.timer(60, SECONDS) // Just to block the main thread for a while
        .blockingSubscribe();

这给出了:

16:54:54 -----> new subscription of subscriber #1
subscriber #1 receives: API call #0
16:54:57 -----> new subscription of subscriber #2
subscriber #2 receives: API call #0
16:55:01 -----> new subscription of subscriber #3
subscriber #1 receives: API call #1
subscriber #2 receives: API call #1
subscriber #3 receives: API call #1
16:55:01 -----> new subscription of subscriber #4
subscriber #4 receives: API call #1
16:55:07 -----> new subscription of subscriber #5
subscriber #1 receives: API call #2
subscriber #2 receives: API call #2
subscriber #3 receives: API call #2
subscriber #4 receives: API call #2
subscriber #5 receives: API call #2
16:55:08 -----> new subscription of subscriber #6
subscriber #6 receives: API call #2
16:55:14 -----> new subscription of subscriber #7
subscriber #1 receives: API call #3
subscriber #2 receives: API call #3
subscriber #3 receives: API call #3
subscriber #4 receives: API call #3
subscriber #5 receives: API call #3
subscriber #6 receives: API call #3
subscriber #7 receives: API call #3

也许我们可以做得更好,但是我现在没有其他想法。

答案 2 :(得分:-1)

您可以使用以下运算符

  1. .retryWhen()运算符以重新订阅。
  2. delay()运算符以延迟订阅者:延迟运算符通过在发出每个源Observable项目之前暂停特定的时间增量(由您指定)来修改其源Observable。这样可以将Observable发出的整个项目序列按时间顺序向前移动指定的增量。