Lukasz Kalnik
07/06/2022, 4:03 PMCallAdapter
for Retrofit which converts the responses to Either<Failure, Success>
type (from the Arrow.kt library).
Now I would like to attach something in the call chain, if the call result is an IOException
then I want to notify the UI that possibly the network connection is gone.
Is there some mechanism to do it?
Currently I tried to attach another CallAdapter
just for this purpose (which basically just should pass the Call unchanged, but as a side-effect emit an event to the UI in the onFailure()
callback of the Call<T>
).
However it doesn't seem to work when put as the first CallAdapter
in chain. There is an error that Moshi converter tries to already parse the call after the first adapter (not waiting for the second one, which outputs the Either<F, S>
type). It complains that it cannot parse JSON to a Call<T>
object.Zac Sweers
07/06/2022, 4:18 PMLukasz Kalnik
07/06/2022, 5:33 PMIOException
is received.CallAdapter
(because I get it from the library and I don't want to fork it). I want to add another adapter just for this case (or something like this).
I guess your library cannot really support me in emitting this side effect, right?CallAdapter
which just passes the request completely unchanged and only emits a side effect under some condition?"IOException
has occurred.
Currently we have in every Presenter/ViewModel the check for this:
apiService.getSomeData().fold(
ifLeft = { if(it is IOError) showConnectionLost() },
ifRight = { /* success case */ }
)
(left/right are error/success cases in Arrow Either type).
And it's very repetitive to check every time if the error is IOError
.Zac Sweers
07/06/2022, 7:36 PMLukasz Kalnik
07/06/2022, 7:37 PMZac Sweers
07/06/2022, 7:38 PMLukasz Kalnik
07/06/2022, 7:38 PMonConnectionLost()
from every Api consumer. I want to have a central place where it is being intercepted for every Api call.Zac Sweers
07/06/2022, 7:39 PMLukasz Kalnik
07/06/2022, 7:40 PMChannel
) as a side effect of receiving an IOExceptionZac Sweers
07/06/2022, 7:41 PMLukasz Kalnik
07/06/2022, 7:41 PMCall<T>
and then Moshi tries to parse it.jw
07/07/2022, 12:30 AMLukasz Kalnik
07/07/2022, 7:43 AMreturnType
. I should unwrap it. Thanks for the hint!getParameterUpperBound(0, returnType)
. I still get the error for not having a converter, although now for the unwrapped type:
java.lang.IllegalArgumentException: Unable to create converter for arrow.core.Either<? extends arrow.retrofit.adapter.either.networkhandling.CallError, de.myapp.gatewayapi.data.remote.air.model.ControlDeviceList>
I suspect the problem is that I now have registered two call adapter factories:
Retrofit.Builder()
.baseUrl(baseUrl)
.client(client)
.addCallAdapterFactory(IOExceptionCallAdapterFactory())
.addCallAdapterFactory(EitherCallAdapterFactory())
.addConverterFactory(MoshiConverterFactory.create(moshiForKotlin))
.build()
.create(AirConnectorApi::class.java)
The first one, IOExceptionCallAdapterFactory
, creates the pass-through adapter, which should not modify the call in any way but only look if there was an IOException
and emit a side effect for the UI.
The second one, EitherCallAdapterFactory
, creates the actual adapter which type-safely wraps success results in Either.Right
and failures or exceptions in Either.Left
.
That means that I want to skip the converter created by MoshiConverterFactory
after the first adapter and only call it after both of the adapters have run. Only then can the response body actually be deserialized.
Is it possible to configure Retrofit to only call the converter after all adapters have run?jw
07/07/2022, 11:46 AMLukasz Kalnik
07/07/2022, 11:46 AMprintln
which I put into `onResponse()`/`onFailure()` inside of IOExceptionCall.enqueque()
(IOExceptionCall
is returned by the pass-through adapter) doesn't register in logs...
Looks like the second adapter is not being called at all.