改造错误响应处理

时间:2018-04-27 06:48:59

标签: error-handling

我正在使用改装2.3.0在我的应用程序中使用API​​但一周前我开始收到错误消息,现有代码无法在UI中显示错误消息。

以前,我使用errorBody.toString()然后在几个月后突然出现错误,然后上周我尝试使用errorBody.string()但它无法正常工作。现在它正在发挥作用。

我附上了服务器响应和我的错误处理的截图。这是我显示错误消息的代码。

private static void showToastForError(retrofit2.Response<Object> response, int requestType) {
        if (response != null && response.errorBody() != null) {
            try {
                JSONObject jObjError = null;
                try {
                    jObjError = new JSONObject(response.errorBody() != null ? response.errorBody().toString() : "");
                    Toast.makeText(Application.getAppContext(), jObjError.getString("message"), Toast.LENGTH_LONG).show();
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

Image contains api response from server

1 个答案:

答案 0 :(得分:0)

我认为你应该自定义调用适配器来处理错误。 这是我的自定义适配器

public final class ErrorHandlingAdapter {
    /**
     * A callback which offers granular callbacks for various conditions.
     */
    public 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);
    }

    public interface MyCall<T> {
        void cancel();

        void enqueue(MyCallback<T> callback);

        MyCall<T> clone();

        boolean isExcute();
    }

    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> {
            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 <R1> R adapt(Call<R1> call) {
                return (R) 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) {

                    // on that executor by submitting a Runnable. This is left as an exercise for the reader.
                    callbackExecutor.execute(new Runnable() {
                        @Override
                        public void run() {
                            int code = response.code();
                            if (code >= 200 && code < 300) {
                                callback.success(response);
                            } else if (code == 401) {
                                if (Storage.getInstance().isLogin())
                                Storage.getInstance().logout(App.self().getApplicationContext());
                            } 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) {

                    // on that executor by submitting a Runnable. This is left as an exercise for the reader.
                    callbackExecutor.execute(new Runnable() {
                        @Override
                        public void run() {
                            if (t instanceof IOException) {
                                if (call.isCanceled()) {
                                    return;
                                }
                                callback.networkError((IOException) t);
                                Toast.makeText(App.self(), R.string.error_no_connect_internet, Toast.LENGTH_SHORT).show();
                            } else {
                                callback.unexpectedError(t);
                            }
                        }
                    });

                }
            });
        }

        @Override
        public MyCall<T> clone() {
            return new MyCallAdapter<>(call.clone(), callbackExecutor);
        }

        @Override
        public boolean isExcute() {
            return call.isExecuted();
        }
    }
}

这是我的配置添加自定义调用适配器

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addCallAdapterFactory(new ErrorHandlingAdapter.ErrorHandlingCallAdapterFactory()) // custom call adapter
                .addConverterFactory(GsonConverterFactory.create())
                .client(getHeader())
                .build();

处理请求,例如:

@GET("api/getSomething")
ErrorHandlingAdapter.MyCall<BaseResponse> getSomething(@Query("param"),...)

处理回应:

ErrorHandlingAdapter.MyCall<BaseResponse> mCalls = ApiUtils.getSomething(...);
    mCalls.enqueue(new ErrorHandlingAdapter.MyCallback<BaseResponse>() {
        @Override
        public void success(Response<BaseResponse> response) {
            //handle response
        }

        @Override
        public void unauthenticated(Response<?> response) {
            //handle unauthenticated error
        }

        @Override
        public void clientError(Response<?> response) {
            //handle clientError error
        }

        @Override
        public void serverError(Response<?> response) {
           //handle serverError error
        }

        @Override
        public void networkError(IOException e) {
           //handle networkError error
        }

        @Override
        public void unexpectedError(Throwable t) {
            //handle unexpectedError error
        }
    }