web-dev-qa-db-ja.com

RetrofitおよびOkHttpClient、失敗メソッドで接続タイムアウトをキャッチ

次のセットアップがあります。

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

私のサーバーがダウンし、ユーザーが接続タイムアウト例外を取得する状況を処理しようとしています、これは私のロギングです:

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

完全なロギング: http://Pastebin.com/gscCGb7x

これを改修失敗メソッドにルーティングして、そこで処理できるようにする方法はありますか?

前もって感謝します!

34
Jdruwe

レトロフィット2の場合

Webサービスインスタンスでリスナーを定義します。

public interface OnConnectionTimeoutListener {
    void onConnectionTimeout();
}

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

インターセプトコードをtry-catchブロックで囲み、例外が発生したときにリスナーに通知します。

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

RetrofitKotlinを使用する場合は、以下の手順に従ってください。

レトロフィットインターフェイスを定義します。

interface GitHubApi {

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

サービスを実装します。

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

必要な場所でサービスを呼び出します。

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

runAsync関数で必要な例外を処理できます。

完全に動作する例 here を取得できます。

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

少し複雑です。 Retrofitを使用すると、同期または非同期のAPI呼び出しを行うことができます。

エンドポイントがvoidを返し、コールバックがある場合、非同期です。何かを返し、コールバックがない場合は同期です。

非同期呼び出しの場合、コールバックのonFailure(...)メソッドでこの例外を受け取ります。

同期呼び出しの場合、呼び出しをtry/catchでラップしない限り、まったく取得しません。

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

更新:上記の回答は、Retrofit 1.9に適用されます。 Retrofit 2.0はこれを大きく変えました。 Retrofit 2.0での現在の動作について疑問がある場合は、この記事でいくつかの指針を示します http://inthecheesefactory.com/blog/retrofit-2.0/en

3
Espen Riskedal

どうやら、例外はRetrofitExceptionにラップされるため、失敗メソッドで処理できます。

3
Jdruwe