在改造2之前,有一种集中处理错误的方法 -
new retrofit.RestAdapter.Builder()
.setEndpoint(apiUrl)
.setLogLevel(retrofit.RestAdapter.LogLevel.FULL)
.setErrorHandler(new CustomErrorHandler(ctx))
但现在在Retrofit 2中,RestAdapter已重命名为Retrofit
且没有setErrorHandler()
。有没有办法使用Retrofit.Builder()
进行集中式错误处理?
答案 0 :(得分:9)
您必须使用自定义服务成功或错误回调制作自定义CallAdapter。杰克沃顿已经成功了。您可以在github
的改造/样品中找到它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);
}
}
}
答案 1 :(得分:3)
Retrofit 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将收到onResponse
中的所有HTTP响应,即使http代码不是2xx或3xx,在这里您需要检查onResponse
方法中的响应状态代码并检查是否响应成功响应(通常为2xx或3xx)并进行正确的逻辑处理。
我已经升级了retrofit2.x,我的集中式错误处理解决方案是: 创建一个使用onSuccess和onFailed两种方法扩展Retrofit.Callback的抽象类,onFailed不是抽象的,因为当业务逻辑失败时我总是执行相同的过程,并在请求成功时执行不同的操作。 您可以参考示例代码here
然后,当你需要发送http请求时,你需要实现onSuccess方法,你也可以在某些情况下覆盖onFailed方法,正如我在项目中提到的,我在大多数情况下以相同的方式处理失败。 您可以参考我使用retrofit2发送帖子请求的示例here。
希望这可以帮到你!
答案 2 :(得分:0)
我使用了与Amir建议类似的解决方案,但我只是想知道这是否可以更容易实现。我尝试了以下方法:
model {
android.sources {
main {
jni {
dependencies {
project ":lib"
// optional:
// buildType "debug" productFlavor "flavor" linkage "static"
}
}
}
}
}
这样我就不需要传递Retrofit实例了。但是我错过了一些东西,因为错误主体未成功解析为StatusResponse。我不确定这在实践中意味着什么:
2.0.0-beta2的更改为回调的onResponse回调提供了Retrofit实例。提供Retrofit对象的边缘情况太多,以允许反序列化错误体。要适应此用例,请手动传递Retrofit响应或实现自定义CallAdapter.Factory自动执行此操作。
答案 3 :(得分:0)
要集中处理特定于401的案件,以及使用新的auth令牌重试请求,请参阅此stack overflow answer。