web-dev-qa-db-de.com

Retrofit und OkHttpClient, Verbindungs-Timeout in Fehlermethode abfangen

Ich habe folgendes Setup:

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);

Ich versuche, mit der Situation umzugehen, in der mein Server ausgefallen ist und der Benutzer eine Ausnahmebedingung für das Verbindungszeitlimit erhält. Dies ist meine Protokollierung:

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

Vollständige Protokollierung: http://Pastebin.com/gscCGb7x

Gibt es eine Möglichkeit, dies in die Retrofit-Fehlermethode umzuleiten, damit ich sie dort verarbeiten kann?

Danke im Voraus!

34
Jdruwe

Für Retrofit 2

Definieren Sie einen Listener in Ihrer Web-Service-Instanz:

public interface OnConnectionTimeoutListener {
    void onConnectionTimeout();
}

Fügen Sie Ihrem Web-Service einen Interceptor hinzu:

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);
}

Schließen Sie Ihren Intercep-Code in einen Try-Catch-Block ein und benachrichtigen Sie den Listener, wenn eine Ausnahme eintritt:

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

Wenn Sie Retrofit in Kotlin verwenden möchten, gehen Sie wie folgt vor:

Definieren Sie Ihre Retrofit-Schnittstelle:

interface GitHubApi {

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

Implementieren Sie Ihren 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)
                }
            }
        }
    }
}

Rufen Sie Ihren Service an, wo Sie wollen:

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

Sie können jede gewünschte Ausnahme in der Funktion runAsync behandeln.

Sie können voll funktionsfähiges Beispiel bekommen hier .

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

Es ist etwas komplizierter. Mit Retrofit können Sie entweder synchrone oder asynchrone API-Aufrufe durchführen.

Wenn Ihr Endpunkt ungültig zurückgibt und einen Rückruf hat, ist er asynchron. Wenn es etwas zurückgibt und keinen Rückruf hat, ist es synchron.

Bei asynchronen Aufrufen erhalten Sie diese Ausnahme in der onFailure(...) -Methode Ihres Rückrufs.

Für synchrone Anrufe bekommen Sie es überhaupt nicht, es sei denn, Sie wickeln Ihren Anruf in ein Try/Catch-Verfahren ein.

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

Update: Die obige Antwort gilt für Retrofit 1.9. Retrofit 2.0 hat dies sehr verändert. Wenn Sie sich fragen, wie die Dinge jetzt in Retrofit 2.0 funktionieren, finden Sie in diesem Artikel einige Hinweise http://inthecheesefactory.com/blog/retrofit-2.0/en

3
Espen Riskedal

Anscheinend wird die Ausnahme in eine RetrofitException eingeschlossen, damit Sie sie in der Fehlermethode behandeln können.

3
Jdruwe