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 PMLukasz Kalnik
07/06/2022, 5:33 PMLukasz Kalnik
07/06/2022, 5:33 PMIOException
is received.Lukasz Kalnik
07/06/2022, 5:34 PMCallAdapter
(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?Lukasz Kalnik
07/06/2022, 5:39 PMCallAdapter
which just passes the request completely unchanged and only emits a side effect under some condition?"Lukasz Kalnik
07/06/2022, 5:43 PMIOException
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 IOExceptionLukasz Kalnik
07/06/2022, 7:41 PMLukasz Kalnik
07/06/2022, 7:41 PMZac Sweers
07/06/2022, 7:41 PMLukasz Kalnik
07/06/2022, 7:41 PMLukasz Kalnik
07/06/2022, 7:41 PMLukasz Kalnik
07/06/2022, 7:42 PMLukasz Kalnik
07/06/2022, 7:42 PMLukasz Kalnik
07/06/2022, 7:44 PMCall<T>
and then Moshi tries to parse it.jw
07/07/2022, 12:30 AMjw
07/07/2022, 12:31 AMjw
07/07/2022, 12:33 AMLukasz Kalnik
07/07/2022, 7:43 AMreturnType
. I should unwrap it. Thanks for the hint!Lukasz Kalnik
07/07/2022, 11:40 AMgetParameterUpperBound(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 AMLukasz Kalnik
07/07/2022, 11:49 AMLukasz Kalnik
07/07/2022, 11:53 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.