改造和集中错误处理

时间:2015-07-26 23:06:34

标签: android android-asynctask retrofit

对服务器的每个请求都可能返回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) {

                    }
                });
            }
        });

如何在一个地方处理所有错误?

5 个答案:

答案 0 :(得分:18)

如果您需要获得一些“逻辑”错误,那么您需要一些Java逻辑,因为它基本上不是Retrofit功能:

  1. 创建实现Retrofit Callback的实现回调
  2. 创建一个定义方法'isError'的基础对象
  3. 修改Retrofit RestAdapter以获取回拨而不是改造一号
  4. 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...)成功

    时,您将收到错误消息

答案 1 :(得分:7)

不确定我是否理解正确,但您可以创建一个Callback并将其作为参数传递给您的所有请求。

而不是:

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

答案 2 :(得分:6)

在Retrofit中,您可以为所有请求指定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();

我认为这就是你要求的。

答案 3 :(得分:1)

在Retrofit2中,您无法使用方法.setErrorHandler()设置ErrorHandler,但您可以创建一个拦截器来集中应用程序某个位置的所有可能错误。

使用此示例,您可以使用Retrofit2和OkHttpClient进行错误处理的集中位置。只需重用Retrofit对象(retrofit)。

您可以使用自定义拦截器尝试此独立示例,以解决网络和服务器错误。这两种方法在Retrofit2中的处理方式不同,因此您必须通过响应代码(response.code())检查服务器返回的错误代码,以及响应是否成功(!response.isSuccessful())。

对于用户没有连接到网络或服务器的情况,您必须捕获方法Response response = chain.proceed(chain.request());的IOException并处理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);
    }
}

答案 4 :(得分:0)

相当简单地改造自定义错误处理示例。设置为使您无需在改装调用的“故障”处理程序中执行大量工作即可显示用户可见的错误消息。适用于所有端点。有很多异常处理,因为我们的服务器人员喜欢通过发送各种随机的东西来保持我们的脚趾..!

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