Building your own Retrofit Call Adapter

httpService.getUsers(12).enqueue(object : Callback<R> {

override fun onFailure(call: Call<R>?, t: Throwable?) {
// handle error
}

override fun onResponse(call: Call<R>?, r: Response<R>?) {
// handle success
}

})

Transforming the retrofit Call object

interface IHttpService {

@GET("users")
fun getUsers(@Query("results") result: Int): Call<List<Users>>

}
interface IHttpService {

@GET("users")
fun getUsers(@Query("results") result: Int): Simple<List<Users>>

}
httpService.getUser(12).process { users, throwable ->
//
handle error or response
}

Defining the Simple Transformer

class Simple<R>(private val call: Call<R>) {
fun run(responseHandler: (R?, Throwable?) -> Unit) {
// run in the same thread
try {
// call and handle response
val response = call.execute()
handleResponse(response, responseHandler)

} catch (t: IOException) {
responseHandler(null, t)
}
}

fun process(responseHandler: (R?, Throwable?) -> Unit) {
// define callback
val callback = object : Callback<R> {

override fun onFailure(call: Call<R>?, t: Throwable?) =
responseHandler(null, t)

override fun onResponse(call: Call<R>?, r: Response<R>?) =
handleResponse(r, responseHandler)
}

// enqueue network call
call.enqueue(callback)
}
private fun handleResponse(response: Response<R>?, handler: (R?, Throwable?) -> Unit) { if (response?.isSuccessful == true) {
handler(response.body(), null)
} else {
if (response?.code() in 400..511)
handler(null, HttpException(response))

else handler(response?.body(), null)

}
}
}
// run synchronously
httpService.getUser(12).run { users, throwable ->
//
handle error or response
}
// run asynchronously
httpService.getUser(12).process { users, throwable ->
//
handle error or response
}

Creating the Call Adapter

class SimpleCallAdapter<R>(private val responseType: Type): CallAdapter<R, Any> {

override fun responseType(): Type = responseType

override fun adapt(call: Call<R>): Any = Simple(call)
}

Defining the Call Adapter Factory

class SimpleCallAdapterFactory private constructor() : CallAdapter.Factory() {

override fun get(returnType: Type?, annotations: Array<out Annotation>?, retrofit: Retrofit?): CallAdapter<*, *>? {
return returnType?.let {
return try {
// get enclosing type
val enclosingType = (it as ParameterizedType)

// ensure enclosing type is 'Simple'
if (enclosingType.rawType != Simple::class.java)
null
else {
val type = enclosingType.actualTypeArguments[0]
SimpleCallAdapter<Any>(type)
}
} catch (ex: ClassCastException) {
null
}
}
}

companion object {
@JvmStatic
fun create() = SimpleCallAdapterFactory()
}

}

Finally adding the Factory to Retrofit

Retrofit retrofit = new Retrofit.Builder()
//... other configs
.addCallAdapterFactory(SimpleCallAdapterFactory.create())
.build();

Other Notes

// create functional interface
public interface SimpleHandler<T> {
void accept(T response, Throwable throwable);
}
class Simple<R>(private val call: Call<R>) {

// support for java
fun run(responseHandler: SimpleHandler<R?>) =
run(responseHandler::accept)
fun process(responseHandler: SimpleHandler<R?>) =
process(responseHandler::accept)
//... other members

}
class Subscription {

private var disposed = false

fun isDisposed() = disposed

fun dispose() {
disposed = true
}
}
class Simple<R>(private val call: Call<R>) {

// ... other memebers
fun process(responseHandler: (R?, Throwable?) -> Unit): Subscription {

val subscription = Subscription()

// define callback
val callback = object : Callback<R> {

override fun onFailure(call: Call<R>?, t: Throwable?) {
if (!subscription.isDisposed())
responseHandler(null, t)
}

override fun onResponse(call: Call<R>?, response: Response<R>?) {
if (!subscription.isDisposed())
handleResponse(response, responseHandler)
}

}

// enqueue network call
call.enqueue(callback)
// return subscription
return subscription
}
// ... other memebers}
val subscription = httpService.getUsers(12).process { r, t ->
//
handle success or response
}


// dispose subscription
subscription.dispose()

Conclusion

A software developer and a mathematical enthusiast. For mentorship find me on code mentor https://www.codementor.io/@ebiigweze

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store