Send correct current time after a retry RxJava and Retrofit

395 Views Asked by At

I'm trying to send to the server the current time at the time the connection is established. I already know that this time may have some latency, regarding the health of the network. For this, I'm using retrofit(2) and rxjava(1), and I have some delay between retries and a retry count, something like this:

 mRetrofit = new ApiClient().getObservableClient();
 mService = mRetrofit.create(ApiObservableService.class);

 mService.sendServerTimeNow(getCurrentTime())
          .observeOn(AndroidSchedulers.mainThread())
          .subscribeOn(Schedulers.io())
          .retryWhen(«new RetryWithDelay(retries, delay))
          .subscribe(new CustomSubscriber<ResponseBody>());

My problem is, every time the retry is made, the getCurrentTime() is not refreshed and its value is always the same on the time of subscription.

E.g. 
 Retry 1 - 1482399029862
 Retry 2 - 1482399029862  //here should be changed to the new current time
 Retry 3 - 1482399029862  //here should be changed to the new current time

I had the felling that retry would re-subscribe, and if this is true is not suppose to refresh the current time?

This is my getCurrentTime()

public long getCurrentTime(){
  return System.currentTimeMillis();
}

How can I accomplish this refresh of current time?

Additionally, I already tried but with no success:

Observable.just(getCurrentTime())
       .flatMap(new Func1<Long, Observable<ResponseBody>>() {
            @Override
            public Observable<ResponseBody> call(Long aLong) {
               mService.sendServerTimeNow(aLong)
            }
        })
        .observeOn(AndroidSchedulers.mainThread())
        .subscribeOn(Schedulers.io())
        .retryWhen(«new RetryWithDelay(retries, delay))
        .subscribe(new CustomSubscriber<ResponseBody>());
2

There are 2 best solutions below

1
On BEST ANSWER

You should first understand that Observable.just(getCurrentTime()) executes getCurrentTime() when the Observable sequence is assembled and doesn't make the call "magically" deferred:

final long now = getCurrentTime();

Observable<Long> o = Observable.just(now);

o.test().assertResult(now); // "now" is set in stone inside the Observable
o.test().assertResult(now);
o.test().assertResult(now);

You can instead have Observable.fromCallable(() -> getCurrentTime()) which will only call getCurrentTime for each incoming subscriber, including the one by retry.

0
On

Let's look at your example with Observable.just :

Observable.just(getCurrentTime())
          .flatMap(...)
          ...

can be rewritten as follow :

Long time = getCurrentTime()
Observable.just(time)
          .flatMap(...)
          ...

A retry will subscribe again to your Observable and will reuse the value of time.

To compute the value again, you'll have to compute the time again, using Observable.fromCallable for example

Observable.fromCallable(() -> getCurrentTime())
          .flatMap(...)
          ...