web-dev-qa-db-fra.com

Utilisez des méthodes de modernisation de manière plus expressive

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?

29

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
    }

}
27
codegames

É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) }))
16
pdpi

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.

6
njzk2

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.
    }
5
Supriya

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)
            }
    )    
1
Ashutosh