I am doing something like this: in my Fragment
, I am observing a LiveData
exposed by a ViewModel
that encapsulates different UI states like error, loading, success state, etc. Within the said ViewModel
, I start an RxJava2 stream that kicks off a chain of REST API requests via Retrofit:
public LiveData<UIState> doSomething() {
compositeDisposable.add(somethingRepo.doA()
.andThen(somethingRepo.doB())
.andThen(somethingRepo.doC())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe(disposable -> status.setValue(UIState.LOADING()))
.subscribe(() -> status.setValue(UIState.SUCCESS()), error -> {
Log.d("SettingsVM", "error: " + error.getClass().getSimpleName());
if(error instanceof VersionAlreadyExistsException) {
status.setValue(UIState.VERSION_EXISTS());
} else {
status.setValue(UIState.ERROR(error.getMessage()));
}
})
);
return status;
}
However, according to my custom logger that implements HttpLoggingInterceptor.Logger
, I am getting a java.net.SocketException: Socket closed
during somethingRepo.doA()
, but it seems that I am not getting the Exception in doSomething()
's onError
. Here is the full somethingRepo.doA()
:
public Completable doA() {
return api.doRequest(paramRepository.getUrl(false),
paramRepository.getAuthorization(),
paramRepository.getName())
.flatMapCompletable(requestResponse-> {
if(paramRepository.getVersion().contentEquals(requestResponse.getVersion())) {
return Completable.error(new VersionAlreadyExistsException());
} else {
return Completable.complete();
}
});
}
api.doRequest is a GET
request that looks like this:
@GET
Single<RequestResponse> doRequest (
@Url String url,
@Header("authorization") String authorization,
@Query("merch") String name);
Interestingly, on another Android app, I sent a POST
to the same URL I am using in the previous example and what I got was HTTP FAILED: java.net.ConnectException: Failed to connect to /180.232.98.122:7443
.
I am aware of a similar issue being opened in the official Retrofit repo and a similar SO question here, but those two are unresolved, thus I would like to hear if anyone here has encountered the same behavior.
I figured out what the problem was. Firstly, I implemented an "inactivity timer" that returns all screens (I use Fragments
for screens) to the first/home screen in my app. So let's say a value of 30 seconds was set to the timer, if no interaction with the UI happens and the timer reaches 30 secs then my app goes back to the home screen.
Secondly, the ViewModel
where I kick off the requests is tied to a Fragment
since it implements DefaultLifecycleObserver
, which means that it will receive LifecycleOwner
changes/callbacks, provided I call this: getViewLifecycleOwner().getLifecycle().addObserver(viewModel)
in my Fragment#onViewCreated
. I then override onStop(@NonNull LifecycleOwner owner)
in the ViewModel
and call compositeDisposable.clear()
, which means I want to sort of cancel all pending API request I made using RxJava2 once the Fragment
my ViewModel
is tied to receives onStop
.
The final piece of info is that the timeout value for my OkHttp
client is greater than the inactivity timer value, so the inactivity timer abruptly causes my request API to be cancelled even before it finishes.
To summarize, here is what happens: when the inactivity timer is up, the request API Fragment
's onStop
is called as the screen changes back to the home screen, and then the ViewModel
calls compositeDisposable.clear()
which disposes the current RxJava disposable, thus I am unable to receive anything on onError
.