2016-01-27 7 views
5

До модернизации 2, был способ обработки erros центрально -Централизованная обработка ошибок смены 2?

new retrofit.RestAdapter.Builder() 
     .setEndpoint(apiUrl) 
     .setLogLevel(retrofit.RestAdapter.LogLevel.FULL) 
     .setErrorHandler(new CustomErrorHandler(ctx)) 

Но теперь в Модернизированный 2, RestAdapter был переименован в Retrofit и нет setErrorHandler(). Есть ли способ централизованной обработки ошибок с использованием Retrofit.Builder()?

ответ

1

После link хорошо объяснил, как решить эту проблему в Модернизированном 2.

Вашей реакция на ошибке:

{ 
    statusCode: 409, 
    message: "Email address already registered" 
} 

Ваша ошибка Класс:

public class APIError { 

    private int statusCode; 
    private String message; 

    public APIError() { 
    } 

    public int status() { 
     return statusCode; 
    } 

    public String message() { 
     return message; 
    } 
} 

И Как обрабатывать ошибки:

public class ErrorUtils { 

    public static APIError parseError(Response<?> response) { 
     Converter<ResponseBody, APIError> converter = 
       ServiceGenerator.retrofit() 
         .responseBodyConverter(APIError.class, new Annotation[0]); 

     APIError error; 

     try { 
      error = converter.convert(response.errorBody()); 
     } catch (IOException e) { 
      return new APIError(); 
     } 

     return error; 
    } 
} 

Ваш запрос должен быть чем-то вроде этого:

Call<User> call = service.me(); 
call.enqueue(new Callback<User>() { 
    @Override 
    public void onResponse(Response<User> response) { 
     if (response.isSuccess()) { 
      // use response data and do some fancy stuff :) 
     } else { 
      // parse the response body … 
      APIError error = ErrorUtils.parseError(response); 
      // … and use it to show error information 

      // … or just log the issue like we’re doing :) 
      Log.d("error message", error.message()); 
     } 
    } 

    @Override 
    public void onFailure(Throwable t) { 
     // there is more than just a failing request (like: no internet connection) 
    } 
}); 

Как вы можете видеть, использовать класс ErrorUtils разобрать тело ошибки и получить объект ApiError.

+0

Имейте в виду, что onFailing также будет срабатывать, если имеется ошибка синтаксического анализа, но тогда вы не будете иметь доступ к телу ответа, чтобы попытаться восстановить ошибку. –

+0

Добрый день. Что такое метод responseBodyConverter? –

+0

@AlexeiKorshun взгляните на [здесь] (https://futurestud.io/blog/retrofit-getting-started-and-android-client) – Amir

3

дооснащения 2,0 переместил ErrorHandler и с использованием нового Callback, который включает в себя два метода:

/** Successful HTTP response. */ 
public void onResponse(Response<T> response, Retrofit retrofit)```` 

/** Invoked when a network or unexpected exception occurred during the HTTP request. */ 
public void onFailure(Throwable t) 

Retrofit2.x будет получать весь ответ HTTP в onResponse, даже если код HTTP не 2xx или 3xx, здесь вам необходимо проверить код состояния ответа в вашем методе onResponse и проверить, соответствует ли ответ ответа ответа (обычно 2xx или 3xx) и выполняет правильную логическую обработку.

Я модернизировал retrofit2.x и мое решение о централизованной обработке ошибки: Создания абстрактного класса, который расширяет Retrofit.Callback с двумя методами OnSuccess и OnFailed, то OnFailed не абстрактно, так как я всегда делаю один и тот же процесс, когда бизнес-логика потерпела неудачу и сделала другую вещь, когда запрос был успешным. Вы можете передать образец кода here

тогда, когда вам нужно отправить запрос HTTP, вы должны реализовать OnSuccess метод, и вы также можете переопределить OnFailed метод в некоторых случаях, как я уже говорил в моем проекте, я обрабатываю в большинстве случаев это не удалось. Вы можете обратиться к примеру here, который я использовал retrofit2 для отправки запроса на отправку.

Надеюсь, это может вам помочь!

0

Я использовал аналогичное решение, предлагаемое Амиром, но мне просто интересно, можно ли это сделать еще проще. Я пробовал следующее:

public void onResponse(Response<T> response) { 
     if (response.isSuccess()) { 
      T resp = response.body(); 
      handleSuccessResponse(resp); 

     } else { 
      Response<StatusResponse> statusResponse = response.error(response.code(), response.errorBody()); 
      handleHttpErrorResponse(statusResponse); 
     } 
    } 

Таким образом, мне не нужно было проходить экземпляр Retrofit. Однако я что-то пропускаю, поскольку тело ошибки не успешно обрабатывается StatusResponse. Я не уверен, что это на практике:

Изменения в версии 2.0.0-beta2, которые предоставили экземпляр Retrofit для обратного вызова обратного вызова onResponse, были возвращены.Слишком много краевых случаев вокруг объекта Retrofit, чтобы разрешить десериализацию тела ошибки. Чтобы приспособить этот прецедент, пропустите ответ «Дооснащение» вручную или выполните собственный CallAdapter.Factory делает это автоматически.

2.0.0-beta3

3

Вы должны сделать пользовательский CallAdapter с успехом или ошибок обратных вызовов пользовательских услуг. Джейк Уортон уже сделал один. Вы можете найти его на модернизированных/образцы

PS: не применимо к версиям до 2.2.0

/* 
* Copyright (C) 2015 Square, Inc. 
* 
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
*  http://www.apache.org/licenses/LICENSE-2.0 
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed under the License is distributed on an "AS IS" BASIS, 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License. 
*/ 
package com.example.retrofit; 

import java.io.IOException; 
import java.lang.annotation.Annotation; 
import java.lang.reflect.ParameterizedType; 
import java.lang.reflect.Type; 
import java.util.concurrent.Executor; 
import retrofit2.Call; 
import retrofit2.CallAdapter; 
import retrofit2.Callback; 
import retrofit2.converter.gson.GsonConverterFactory; 
import retrofit2.Response; 
import retrofit2.Retrofit; 
import retrofit2.http.GET; 

/** 
* A sample showing a custom {@link CallAdapter} which adapts the built-in {@link Call} to a custom 
* version whose callback has more granular methods. 
*/ 
public final class ErrorHandlingAdapter { 
    /** A callback which offers granular callbacks for various conditions. */ 
    interface MyCallback<T> { 
    /** Called for [200, 300) responses. */ 
    void success(Response<T> response); 
    /** Called for 401 responses. */ 
    void unauthenticated(Response<?> response); 
    /** Called for [400, 500) responses, except 401. */ 
    void clientError(Response<?> response); 
    /** Called for [500, 600) response. */ 
    void serverError(Response<?> response); 
    /** Called for network errors while making the call. */ 
    void networkError(IOException e); 
    /** Called for unexpected errors while making the call. */ 
    void unexpectedError(Throwable t); 
    } 

    interface MyCall<T> { 
    void cancel(); 
    void enqueue(MyCallback<T> callback); 
    MyCall<T> clone(); 

    // Left as an exercise for the reader... 
    // TODO MyResponse<T> execute() throws MyHttpException; 
    } 

    public static class ErrorHandlingCallAdapterFactory extends CallAdapter.Factory { 
    @Override public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, 
     Retrofit retrofit) { 
     if (getRawType(returnType) != MyCall.class) { 
     return null; 
     } 
     if (!(returnType instanceof ParameterizedType)) { 
     throw new IllegalStateException(
      "MyCall must have generic type (e.g., MyCall<ResponseBody>)"); 
     } 
     Type responseType = getParameterUpperBound(0, (ParameterizedType) returnType); 
     Executor callbackExecutor = retrofit.callbackExecutor(); 
     return new ErrorHandlingCallAdapter<>(responseType, callbackExecutor); 
    } 

    private static final class ErrorHandlingCallAdapter<R> implements CallAdapter<R, MyCall<R>> { 
     private final Type responseType; 
     private final Executor callbackExecutor; 

     ErrorHandlingCallAdapter(Type responseType, Executor callbackExecutor) { 
     this.responseType = responseType; 
     this.callbackExecutor = callbackExecutor; 
     } 

     @Override public Type responseType() { 
     return responseType; 
     } 

     @Override public MyCall<R> adapt(Call<R> call) { 
     return new MyCallAdapter<>(call, callbackExecutor); 
     } 
    } 
    } 

    /** Adapts a {@link Call} to {@link MyCall}. */ 
    static class MyCallAdapter<T> implements MyCall<T> { 
    private final Call<T> call; 
    private final Executor callbackExecutor; 

    MyCallAdapter(Call<T> call, Executor callbackExecutor) { 
     this.call = call; 
     this.callbackExecutor = callbackExecutor; 
    } 

    @Override public void cancel() { 
     call.cancel(); 
    } 

    @Override public void enqueue(final MyCallback<T> callback) { 
     call.enqueue(new Callback<T>() { 
     @Override public void onResponse(Call<T> call, Response<T> response) { 
      // TODO if 'callbackExecutor' is not null, the 'callback' methods should be executed 
      // on that executor by submitting a Runnable. This is left as an exercise for the reader. 

      int code = response.code(); 
      if (code >= 200 && code < 300) { 
      callback.success(response); 
      } else if (code == 401) { 
      callback.unauthenticated(response); 
      } else if (code >= 400 && code < 500) { 
      callback.clientError(response); 
      } else if (code >= 500 && code < 600) { 
      callback.serverError(response); 
      } else { 
      callback.unexpectedError(new RuntimeException("Unexpected response " + response)); 
      } 
     } 

     @Override public void onFailure(Call<T> call, Throwable t) { 
      // TODO if 'callbackExecutor' is not null, the 'callback' methods should be executed 
      // on that executor by submitting a Runnable. This is left as an exercise for the reader. 

      if (t instanceof IOException) { 
      callback.networkError((IOException) t); 
      } else { 
      callback.unexpectedError(t); 
      } 
     } 
     }); 
    } 

    @Override public MyCall<T> clone() { 
     return new MyCallAdapter<>(call.clone(), callbackExecutor); 
    } 
    } 
} 
Смежные вопросы