Je veux rendre le bloc de code d'invocation de la méthode void enqueue(Callback<T> callback);
plus expressif, voici ce que j'ai habituellement
request.enqueue(object : Callback<MyModel> {
override fun onFailure(call: Call<MyModel>?, t: Throwable?) {
//
}
override fun onResponse(call: Call<MyModel>?, response: Response<MyModel>?) {
//
}
})
Et ce que je veux et veux dire, c'est que, pour changer ce code, bloquez de manière plus propre et supprimez ces mots-clés override, object, Callback et faites quelque chose comme ça:
request.enqueue({throwable, response -> })
Je pense qu'il pourrait être amélioré d'une manière ou d'une autre en utilisant des extensions et des fonctions d'ordre supérieur. Est-ce que quelqu'un sait comment cela peut être fait?
voici comment je le fais avec la fonction d'extension et une classe
fun<T> Call<T>.enqueue(callback: CallBackKt<T>.() -> Unit) {
val callBackKt = CallBackKt<T>()
callback.invoke(callBackKt)
this.enqueue(callBackKt)
}
class CallBackKt<T>: Callback<T> {
var onResponse: ((Response<T>) -> Unit)? = null
var onFailure: ((t: Throwable?) -> Unit)? = null
override fun onFailure(call: Call<T>, t: Throwable) {
onFailure?.invoke(t)
}
override fun onResponse(call: Call<T>, response: Response<T>) {
onResponse?.invoke(response)
}
}
alors vous pouvez l'utiliser comme ça
request.enqueue {
onResponse = {
// do
}
onFailure = {
// do
}
}
Étant donné la fonction suivante:
fun <T> callback(fn: (Throwable?, Response<T>?) -> Unit): Callback<T> {
return object : Callback<T> {
override fun onResponse(call: Call<T>, response: retrofit2.Response<T>) = fn(null, response)
override fun onFailure(call: Call<T>, t: Throwable) = fn(t, null)
}
}
Vous pouvez l'utiliser avec Retrofit comme ceci:
request.enqueue(callback({ throwable, response ->
response?.let { callBack.onResponse(response.body() ?: RegisterResponse()) }
throwable?.let { callBack.onFailed(throwable.message!!) })
Alternativement, vous pouvez définir cette autre version de rappel:
fun <T> callback2(success: ((Response<T>) -> Unit)?, failure: ((t: Throwable) -> Unit)? = null): Callback<T> {
return object : Callback<T> {
override fun onResponse(call: Call<T>, response: retrofit2.Response<T>) { success?.invoke(response) }
override fun onFailure(call: Call<T>, t: Throwable) { failure?.invoke(t) }
}
}
qui peut être utilisé comme ceci:
request.enqueue(callback2(
{ r -> callBack.onResponse(r.body()) },
{ t -> callBack.onFailed(t.message) }))
Ce que vous pouvez faire est le suivant (c'est Java car je ne connais pas beaucoup Kotlin, mais cela devrait être assez similaire):
public class CallbackWrapper<T> implements Callback<T> {
private Wrapper<T> wrapper;
public CallbackWrapper(Wrapper<T> wrapper) {
this.wrapper = wrapper;
}
public void onFailure(Call<T> call, Throwable t) {
wrapper.onResult(t, null);
}
public void onResponse(Call<T> call, Response<T> response) {
wrapper.onResult(null, response);
}
public static interface Wrapper<T> {
void onResult(Throwable t, Response<T> response);
}
}
Que vous pouvez utiliser comme:
call.enqueue(new CallbackWrapper((throwable, reponse) - > {...}));
solution de mise à jour pour kotlin:
Basé sur this , le CallBackWrapper
ressemble à ceci:
typealias wrapper<T> = (t: Throwable?, response: Response<T>?) -> Unit
class CallbackWrapper<T>(val wrapper: wrapper<T>) : Callback<T> {
override fun onFailure(call: Call<T>?, t: Throwable?) = wrapper.invoke(t,null)
override fun onResponse(call: Call<T>?, response: Response<T>?) = wrapper.invoke(null, response)
}
et l'utiliser comme Java.
J'ai utilisé une fonction d'extension sur Call
pour écrire une méthode expressive et générique enqueue
.
fun<T> Call<T>.onEnqueue(actOnSuccess: (Response<T>) -> Unit, actOnFailure: (t: Throwable?) -> Unit) {
this.enqueue(object: Callback<T> {
override fun onFailure(call: Call<T>?, t: Throwable?) {
actOnFailure(t)
}
override fun onResponse(call: Call<T>?, response: Response<T>) {
actOnSuccess(response)
}
})
}
Cela peut ensuite être utilisé comme:
request.onEnqueue {
actOnSuccess = {
doOnSuccess()
}
actOnFailure = {
doOnFailure()
}
}
Dans les blocs de code actOnSuccess et actOnFailure, it
doit faire référence aux objets Response
et Throwable
respectivement, et peut être exploité en conséquence. Par exemple, dans le bloc de code actOnFailure -
actOnFailure = {
doOnFailure()
//it.message //'it' refers to the Throwable object.
}
Vous pouvez créer une fonction d'extension comme celle-ci
inline fun <T> Call<T>.addEnqueue(
crossinline onSuccess: (response: Response<T>) -> Unit = { response: Response<T> -> },
crossinline onFail: (t: Throwable) -> Unit = { throwable: Throwable ->}
):Callback<T> {
val callback = object : Callback<T> {
override fun onFailure(call: Call<T>, t: Throwable) {
onFail(t)
}
override fun onResponse(call: Call<T>, response: Response<T>) {
onSuccess(response)
}
}
enqueue(callback)
return callback
}
et l'utiliser comme ça dans votre activité ou fragment
service?.fetchUser()?.addEnqueue(
onSuccess = {
doOnSuccess(it)
},
onFail = {
doOnFail(it)
}
)