在Rx中,如何正确循环网络呼叫?

时间:2015-03-15 22:28:04

标签: reactive-programming rx-java

我有一个网络调用,它返回一个项目列表。我想继续重复该网络呼叫,直到项目数量与初始计数不同,或者已经过了5秒。我试过这个:

timer = 0;
while (initialCount== afterCount && timer != 5) {
  try {
    Thread.sleep(1000);
    timer++;
    Observable<List<Item>> itemObservable = getItemsFromNetwork();
    itemObservable.subscribe(new Observer<List<Item>>() {
                                 @Override public void onCompleted()   
                                 { Log.d("DEBUG", "onCompleted"); }

                                 @Override public void onError(
                                 Throwable e) { Log.d("DEBUG", "e"; }

                                 @Override public void onNext(
                                 List<Item> items) {
                                   afterCount=items.size();
                                   Log.d("DEBUG", "onNext, " +  
                                   afterCount + " items.  "  
                                   + timer + " secs passed");
                                 }
                               });
} catch (Exception e) { }

我已经确认initialCount总是5,所以我很困惑为什么会打印出来:

onNext, 5 items.  1 seconds passed
onCompleted
onNext, 5 items.  2 seconds passed
onCompleted
onNext, 4 items.  3 seconds passed
onCompleted
onNext, 4 items.  4 seconds passed
onCompleted

最后的onNext不应该被命中,因为循环应该已经爆发了。实施它的正确方法是什么?谢谢

1 个答案:

答案 0 :(得分:0)

这应该做你想要的(检查它编译,但不是它的工作原理):

        var x = Observable.Interval(TimeSpan.FromSeconds(1))
            .Take(5)
            .SelectMany(_ => getItemsFromNetwork())
            .DistinctUntilChanged(l1 => l1.Count)
            .Take(2);

我认为这完成了你想要做的大部分工作:

  • 每秒轮询一次。
  • 仅轮询5次
  • 它仅传递元素数已更改的那些。
  • 它将传递第一个(initialCount),然后传递一个已经改变的。

如何初始化上面的initialCount并没有完全指定,所以这可能做不到正确的事情。另外,我还在学习Take到底是如何工作的:我80%确定如果前两个调用返回不同的数字,getItemsFromNetwork只会被调用两次。

如果你的情况是initialCount来自程序中的其他地方,而不是来自调用fragmet到getItemsFromNetowkr之前的电话,那么也许你可以用一个简单的Where替换DistinctUntilChagned行吗?

        var x = Observable.Interval(TimeSpan.FromSeconds(1))
            .Take(5)
            .SelectMany(_ => getItemsFromNetwork())
            .Where(l1 => l1.Count != intialCount)
            .Take(1);

最后,在这两种情况下,你都使用上面的调试语句订阅x,它应该可以工作。