web-dev-qa-db-fra.com

Retrofit et OkHttpClient, intercepte le délai de connexion dans la méthode d'échec

J'ai la configuration suivante:

final OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setReadTimeout(5, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(5, TimeUnit.SECONDS);

RestAdapter.Builder builder = new RestAdapter.Builder()
        .setEndpoint(ROOT)
        .setClient(new OkClient(okHttpClient))
        .setLogLevel(RestAdapter.LogLevel.FULL);

J'essaie de gérer la situation dans laquelle mon serveur est en panne et que l'utilisateur obtient une exception de délai de connexion, voici mon enregistrement:

Java.net.SocketTimeoutException: failed to connect to /192.168.0.53 (port 3000) after 5000ms

Consignation complète: http://Pastebin.com/gscCGb7x

Existe-t-il un moyen d’envoyer cela dans la méthode d’échec de rattrapage afin que je puisse le gérer là-bas?

Merci d'avance!

34
Jdruwe

Pour la modification 2

Définissez un auditeur dans votre instance de service Web:

public interface OnConnectionTimeoutListener {
    void onConnectionTimeout();
}

Ajoutez un intercepteur à votre service Web:

public WebServiceClient() {
    OkHttpClient client = new OkHttpClient();
    client.setConnectTimeout(10, TimeUnit.SECONDS);
    client.setReadTimeout(30, TimeUnit.SECONDS);
    client.interceptors().add(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            return onOnIntercept(chain);
        }
    });
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .build();
    webService = retrofit.create(WebService.class);
}

Placez votre code intercep avec le bloc try-catch et avertissez l'écouteur lorsqu'une exception se produit:

private Response onOnIntercept(Chain chain) throws IOException {
    try {
        Response response = chain.proceed(chain.request());
        String content = UtilityMethods.convertResponseToString(response);
        Log.d(TAG, lastCalledMethodName + " - " + content);
        return response.newBuilder().body(ResponseBody.create(response.body().contentType(), content)).build();
    }
    catch (SocketTimeoutException exception) {
        exception.printStackTrace();
        if(listener != null)
            listener.onConnectionTimeout();
    }

    return chain.proceed(chain.request());
}

Kotlin

Si vous souhaitez utiliser Retrofit dans Kotlin, suivez les étapes ci-dessous:

Définissez votre interface de mise à niveau:

interface GitHubApi {

    @GET("/users/{userName}/repos")
    fun repos(@Path("userName") userName: String): Call<List<Repo>>
}

Implémentez votre service:

class Api(...) {

    private val baseUrl = "https://api.github.com"
    private val api: GitHubApi

    private fun loggingInterceptor(...): HttpLoggingInterceptor {...}

    private fun okHttpBuilder(): OkHttpClient {...}

    init {...}

    fun repos(
        userName: String,
        onSuccess: (list: List<Repo>?) -> Unit,
        onFailure: (message: String?) -> Unit): Future<Unit> {
        return runAsync(api.repos(userName), onSuccess, onFailure)
    }

    private fun <T> runAsync(
        call: retrofit2.Call<T>,
        onSuccess: (T?) -> Unit,
        onFailure: (message: String?) -> Unit) : Future<Unit> {
        return doAsync {
            try {
                val response = call.execute()
                when {
                    response.isSuccessful -> response.body()?.let {
                        onSuccess(it)
                    }
                    else -> {
                        onFailure(response.raw().message())
                    }
                }
            } catch (e: IOException) {
                if (e is SocketTimeoutException) {
                    onFailure("Response time out!")
                } else {
                    onFailure(e.message)
                }
            }
        }
    }
}

Appelez votre service là où vous le souhaitez:

Api().repos("olcayertas",
    onSuccess = {
        Log.d("MainActivity", "Response:\n" + toJson(it))
    },
    onFailure = {
        Log.e("MainActivity", "Error: $it")
    })

Vous pouvez gérer n'importe quelle exception de votre choix dans la fonction runAsync.

Vous pouvez obtenir un exemple pleinement fonctionnel ici .

45
Olcay Ertaş
 @Override
    public void onFailure(Call call, Throwable t) {
        if(t instanceof SocketTimeoutException){
            message = "Socket Time out. Please try again.";
        }
    }
34
Bhavya V

C'est un peu plus compliqué. Avec Retrofit, vous pouvez effectuer des appels d'API synchrones ou asynchrones.

Si votre terminal retourne null et qu'il est rappelé, il est asynchrone. S'il renvoie quelque chose et qu'il n'a pas de rappel, c'est synchrone.

Pour les appels asynchrones, vous obtenez cette exception dans la méthode onFailure(...) de votre rappel.

Pour les appels synchrones, vous ne l'obtenez pas du tout, sauf si vous envelopper l'appel dans un essai/attraper.

try {
   // your synchronous call goes here  
} catch (RetrofitError error) {
   // handle errors
}

Mise à jour: La réponse ci-dessus s’applique à Retrofit 1.9. Retrofit 2.0 a beaucoup changé cela. Si vous vous demandez comment les choses fonctionnent maintenant dans Retrofit 2.0, cet article donne des indications http://inthecheesefactory.com/blog/retrofit-2.0/fr

3
Espen Riskedal

Apparemment, l'exception est encapsulée dans une exception RetrofitException afin que vous puissiez la gérer avec la méthode d'échec.

3
Jdruwe