Подтвердить что ты не робот

Модернизация и централизованная обработка ошибок

Каждый запрос на сервер может возвращать error_code. Я хочу обработать эту ошибку в одном месте когда я использовал AsyncTask, у меня был такой же BaseAsyncTask

public abstract class BaseAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {

    protected Context context;
    private ProgressDialog progressDialog;
    private Result result;

    protected BaseAsyncTask(Context context, ProgressDialog progressDialog) {
        this.context = context;
        this.progressDialog = progressDialog;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    @Override
    protected void onPostExecute(Result result) {
        super.onPostExecute(result);
        HttpResponse<ErrorResponse> response = (HttpResponse<ErrorResponse>) result;
     if(response.getData().getErrorCode() != -1) {
                handleErrors(response.getData());
        }else 
            onResult(result);

    }

    private void handleErrors(ErrorResponse errorResponse) {
    }
     public abstract void onResult(Result result);
    }

Но, используя модификацию, каждый запрос имеет обратный вызов обработки ошибок:

                    git.getFeed(user,new Callback<gitmodel>() {
                    @Override
                    public void success(gitmodel gitmodel, Response response) {

                    }

                    @Override
                    public void failure(RetrofitError error) {

                    }
                });
            }
        });

Как я могу обрабатывать все ошибки в одном месте?

4b9b3361

Ответ 1

Если вам нужно получить некоторую "логическую" ошибку, вам понадобится Java-логика, так как она не является функцией "Дооснащение" в основном:

  • Создайте свою реализацию Обратный вызов, который реализует обратный вызов с обновлением
  • Создайте базовый объект, который определяет метод isError
  • Измените вариант RestAdapter для перенастройки, чтобы получить обратный вызов вместо новой версии

MyCallback.java

import android.util.Log;
import retrofit.Callback;
import retrofit.client.Response;

public abstract class MyCallback<T extends MyObject> implements Callback<T> {

    @Override
    public final void success(T o, Response response) {
        if (o.isError()) {
            // [..do something with error]
            handleLogicError(o);
        }
        else {
            handleSuccess(o, response);
        }
    }

    abstract void handleSuccess(T o, Response response);

    void handleLogicError(T o) {
        Log.v("TAG", "Error because userId is " + o.id);
    }
}

MyObject.java(базовый класс для всех ваших объектов, которые вы получаете от Retrofit)

public class MyObject {
    public long id;
    public boolean isError() {
        return id == 1;
    }
}

MyRealObject.java - класс, который расширяет базовый объект

public class MyRealObject extends MyObject {
    public long userId;
    public String title;
    public String body;
}

RetroInterface.java - интерфейс, используемый для модификации, должен быть знаком с

import retrofit.http.GET;
import retrofit.http.Path;

public interface RetroInterface {

    @GET("/posts/{id}")
    void sendGet(@Path("id") int id, MyCallback<MyRealObject> callback);

}

И, наконец, фрагмент кода, в котором вы используете всю логику

    RestAdapter adapter = new RestAdapter.Builder()
            .setEndpoint("http://jsonplaceholder.typicode.com")
            .build();

    RetroInterface itf = adapter.create(RetroInterface.class);
    itf.sendGet(2, new MyCallback<MyRealObject>() {
        @Override
        void handleSuccess(MyRealObject o, Response response) {
            Log.v("TAG", "success");
        }

        @Override
        public void failure(RetrofitError error) {
            Log.v("TAG", "failure");
        }
    });

Если вы скопируете и вставьте этот код, вы получите сообщение об ошибке при выполнении itf.sendGet(1, new MyCallback..) и успеха для itf.sendGet(2, new MyCallback...)

Ответ 2

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

Вместо:

            git.getFeed(user,new Callback<gitmodel>() {
                @Override 
                public void success(gitmodel gitmodel, Response response) { 

                } 

                @Override 
                public void failure(RetrofitError error) { 

                } 
            }); 

Сначала определите свой Обратный вызов:

Callback<gitmodel> mCallback = new Callback<gitmodel>() {
    @Override 
    public void success(gitmodel gitmodel, Response response) { 

    } 

    @Override 
    public void failure(RetrofitError error) { 
        // logic to handle error for all requests
    } 
};

Тогда:

git.getFeed(user, mCallback);

Ответ 3

В "Дополнении" вы можете указать ErrorHandler для всех запросов.

public class ApiErrorHandler implements ErrorHandler {

    @Override
    public Throwable handleError(RetrofitError cause) {
        //here place your logic for all errors
        return cause;
    }
}

Примените его к RestAdapter

RestAdapter.Builder()
            .setClient(client)
            .setEndpoint(endpoint)
            .setErrorHandler(errorHandler)
            .build();

Я думаю, что это то, о чем вы просили.

Ответ 4

В Retrofit2 вы не можете установить ErrorHandler с помощью метода .setErrorHandler(), но вы можете создать перехватчик, чтобы развернуть все возможные ошибки, централизованные в одном месте вашего приложения.

В этом примере у вас есть одно централизованное место для обработки ошибок с помощью Retrofit2 и OkHttpClient. Просто повторите использование объекта Retrofit (retrofit).

Вы можете попробовать этот отдельный пример с помощью специального перехватчика для сетевых и серверных ошибок. Эти два варианта будут обрабатываться по-разному в Retrofit2, поэтому вам нужно проверить возвращаемый код ошибки с сервера по коду ответа (response.code()), и если ответ не был успешным (!response.isSuccessful()).

В случае, если у пользователя нет соединения с сетью или сервером, вы должны поймать IOException метода Response response = chain.proceed(chain.request()); и обработать сетевую ошибку в блоке catch.

HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
    loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

    OkHttpClient client = new OkHttpClient.Builder()
            .addInterceptor(loggingInterceptor)
            .addInterceptor(new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    try {
                        Response response = chain.proceed(chain.request());
                        if (!response.isSuccessful()) {
                            Log.e("tag", "Failure central - response code: " + response.code());
                            Log.e("tag", "central server error handling");

                            // Central error handling for error responses here:
                            // e.g. 4XX and 5XX errors
                            switch (response.code()) {
                                case 401:
                                    // do something when 401 Unauthorized happened
                                    // e.g. delete credentials and forward to login screen
                                    // ...

                                    break;
                                case 403:
                                    // do something when 403 Forbidden happened
                                    // e.g. delete credentials and forward to login screen
                                    // ...

                                    break;
                                default:
                                    Log.e("tag", "Log error or do something else with error code:" + response.code());

                                    break;
                            }
                        }

                        return response;
                    } catch (IOException e) {
                        // Central error handling for network errors here:
                        // e.g. no connection to internet / to server

                        Log.e("tag", e.getMessage(), e);
                        Log.e("tag", "central network error handling");

                        throw e;
                    }
                }
            })
            .build();

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://10.0.2.2:8000/api/v1/")
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    UserRepository backendRepository = retrofit.create(UserRepository.class);
    backendRepository.getUser("userId123").enqueue(new Callback<UserModel>() {
        @Override
        public void onResponse(Call<UserModel> call, retrofit2.Response<UserModel> response) {
            Log.d("tag", "onResponse");

            if (!response.isSuccessful()) {
                Log.e("tag", "onFailure local server error handling code:" + response.code());
            } else {
                // its all fine with the request


            }
        }

        @Override
        public void onFailure(Call<UserModel> call, Throwable t) {
            Log.e("tag", "onFailure local network error handling");
            Log.e("tag", t.getMessage(), t);

        }
    });

Пример UserRepository:

public interface UserRepository {
    @GET("users/{userId}/")
    Call<UserModel> getUser(@Path("userId") String userId);

}

Пример UserModel:

public class UserModel implements Parcelable {
    @SerializedName("id")
    @Expose
    public String id = "";

    @SerializedName("email")
    @Expose
    public String mail = "";

    public UserModel() {

    }

    protected UserModel(Parcel in) {
        id = in.readString();
        mail = in.readString();
    }

    public static final Creator<UserModel> CREATOR = new Creator<UserModel>() {
        @Override
        public UserModel createFromParcel(Parcel in) {
            return new UserModel(in);
        }

        @Override
        public UserModel[] newArray(int size) {
            return new UserModel[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(id);
        dest.writeString(mail);
    }
}

Ответ 5

Достаточно просто переделать пример обработки пользовательских ошибок. Устанавливается таким образом, что вам не нужно много работать в обработчике "сбоя" вызова для переоснащения, чтобы показать отображаемое пользователем сообщение об ошибке. Работает на всех конечных точках. Там много обработки исключений, поскольку наши люди-серверы любят держать нас на своих ногах, отправляя всевозможные случайные вещи..!

     retrofit-custom-error-handling.java
    // on error the server sends JSON
    /*
    { "error": { "data": { "message":"A thing went wrong" } } }
    */
    // create model classes..
    public class ErrorResponse {
    Error error;
    public static class Error {
    Data data;
    public static class Data {
    String message;
    }
    }
    }
    //
    /**
    * Converts the complex error structure into a single string you can get with error.getLocalizedMessage() in Retrofit error handlers.
    * Also deals with there being no network available
    *
    * Uses a few string IDs for user-visible error messages
    */
    private static class CustomErrorHandler implements ErrorHandler {
    private final Context ctx;

    public CustomErrorHandler(Context ctx) {
        this.ctx = ctx;
    }

    @Override
    public Throwable handleError(RetrofitError cause) {
        String errorDescription;
        if (cause.isNetworkError()) {
            errorDescription = ctx.getString(R.string.error_network);
        } else {
            if (cause.getResponse() == null) {
                errorDescription = ctx.getString(R.string.error_no_response);
            } else {
// Error message handling - return a simple error to Retrofit handlers..
                try {
                    ErrorResponse errorResponse = (ErrorResponse) cause.getBodyAs(ErrorResponse.class);
                    errorDescription = errorResponse.error.data.message;
                } catch (Exception ex) {
                    try {
                        errorDescription = ctx.getString(R.string.error_network_http_error, cause.getResponse().getStatus());
                    } catch (Exception ex2) {
                        Log.e(TAG, "handleError: " + ex2.getLocalizedMessage());
                        errorDescription = ctx.getString(R.string.error_unknown);
                    }
                }
            }
        }
        return new Exception(errorDescription);
    }
}
// When creating the Server...
retrofit.RestAdapter restAdapter = new retrofit.RestAdapter.Builder()
        .setEndpoint(apiUrl)
        .setLogLevel(retrofit.RestAdapter.LogLevel.FULL)
        .setErrorHandler(new CustomErrorHandler(ctx)) // use error handler..
        .build();
server=restAdapter.create(Server.class);
// Now when calling server methods, get simple error out like this:
        server.postSignIn(login,new Callback<HomePageResponse>(){
@Override
public void success(HomePageResponse homePageResponse,Response response){
// Do success things!
        }
@Override
public void failure(RetrofitError error){
        error.getLocalizedMessage(); // <-- this is the message to show to user.
        }
        });