0

What I would like to do is create a function which runs another function every second. The second function returns Observables<A> and I want the first function to return Observables<A> as well instead of Observable<Observable<A>>

for example:

private A calcA(){
   ...
   return new A(...)
}

public Observable<A> getAs(){
   return Observable.create( subscriber -> {
      Bool condition = ...
      do {
         subscriber.onNext(calcA())
      } while (condition)
      subscriber.onComplete()
   })
}

public Observable<A> pollAs(){
   return Observable.create(subscriber -> {
      do {
         subscriber.onNext(getAs()) // Flatten here I guess
         Thread.sleep(1000)
      } while(true)
   })

So I would like to do something similar (I tried to write this in a Java-ish way, but I will use Kotlin)

godzsa
  • 2,105
  • 4
  • 34
  • 56

2 Answers2

2

You don't need to use the flatMap() operator to flatten the inner observable, since you only want to repeatedly subscribe to the same observable.

public Observable<A> getAs() {
   return Observable.fromCallable( () -> calcA() )
            .repeat()
            .takeWhile( v -> !condition( v );
}

getAs() will emit items until the condition has been reached. It will then complete.

public Observable<A> pollAs(){
   return getAs()
            .repeatWhen( completed -> completed.delay(1000, TimeUnit.MILLISECONDS) );

pollAs() will continually resubscribe to the getAs() observable, pausing for a second between each subscription.

Edit: I have uploaded a 6-month-duration example to https://pastebin.com/kSmi24GF It shows that you have to keep advancing the time for data to come out.

Bob Dalgleish
  • 8,167
  • 4
  • 32
  • 42
  • 1
    This looks so beautiful it warms my heart :D – godzsa Apr 20 '18 at 08:56
  • One more question, please. In another scenario I call `calcAs` which returns a list of `A`-s and I want to emit them one by one. Shall I put a `flatMap(items -> Observable.fromIterable(items))` before the `repeat()` or is there a better solution? – godzsa Apr 20 '18 at 11:44
  • Also `repeatWhen` only repeats the `getAs()` once, and does not do that over and over again, should I use `repeatUntil` instead? – godzsa Apr 20 '18 at 11:47
  • 1
    `repeatWhen()` takes a function that returns an Observable. When `onComplete` on the original observable occurs, it emits a value to the observable, which emits either a value, in which case the original observable is resubscribed, or `onComplete`/`onError` which doesn't. In other words, it will repeat forever. – Bob Dalgleish Apr 20 '18 at 13:21
  • For me this does not repeat repeat forever :( – godzsa Apr 20 '18 at 15:19
  • @godza I run the above code in a unit test, and it renewed each time. – Bob Dalgleish Apr 20 '18 at 15:39
  • Can you upload the code to pastebin? I don't know what I am missing – godzsa Apr 20 '18 at 16:32
0

I came up with this solution:

public Observable<A> pollAs() {
   return Observable.create(subscriber -> {
       do {
           getAs().subscribe(
                   { subscriber.onNext(it) },
                   { subscriber.onError(it) },
                   { Thread.sleep(1000) }
           )
       } while (true)
   })
}

I don't really like this one can someone show me a more convenient way?

godzsa
  • 2,105
  • 4
  • 34
  • 56