自定义呼叫适配器改造中的通用类型
Posted
技术标签:
【中文标题】自定义呼叫适配器改造中的通用类型【英文标题】:Generic type in retrofit for the custom call adapter 【发布时间】:2018-06-02 20:48:53 【问题描述】:改造异步请求是回调,有 2 个方法 onResponse() 和 onFailure()。
我不想总是重写这两种方法并处理错误情况。
所以当我想通过 ApiResponse 的谷歌 GithubBrowserSample 包装改造响应正文并将错误转换如下:
public class ApiResponse<T>
public final int code;
@Nullable
public final T body;
@Nullable
public final String errorMessage;
public ApiResponse(Throwable error)
code = -1;
body = null;
if (error instanceof IOException)
errorMessage = "No network error";
else
errorMessage = error.getMessage();
public ApiResponse(Response<T> response)
code = response.code();
if (response.isSuccessful())
body = response.body();
errorMessage = null;
else
String message = null;
if (response.errorBody() != null)
try
message = response.errorBody().string();
catch (IOException e)
e.printStackTrace();
if (message == null || message.trim().length() == 0)
message = response.message();
errorMessage = message;
body = null;
public boolean isSuccessful()
return code >= 200 && code < 300;
我也想用 Gson 转换器来转换改造响应,然后用 ApiResponse 包装。
如果我喜欢使用
Call<ApiResponse<Result>> requestCall = webClient.request1(xxx,xxx);
requestCall.enqueue(new Callback<ApiResponse<Result>> );
好像不行。 json 响应数据无法解析为 Result 对象。
所以我考虑编写我自己的自定义呼叫适配器引用 retrofit sample 来替换改造呼叫。但是我仍然有转换泛型类型的问题。
public class MyCallAdapterFactory extends CallAdapter.Factory
@Nullable
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit)
if (getRawType(returnType) != MyCall.class)
return null;
Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
Class<?> rawObservableType = getRawType(observableType);
if (rawObservableType != ApiResponse.class)
throw new IllegalArgumentException("type must be a resource");
if (! (observableType instanceof ParameterizedType))
throw new IllegalArgumentException("resource must be parameterized");
Type bodyType = getParameterUpperBound(0, (ParameterizedType) observableType);
Executor executor = retrofit.callbackExecutor();
return new MyCallAdapter<>(bodyType, executor);
public class MyCallAdapter<T> implements CallAdapter<T, MyCall<T>>
private final Type responseType;
private final Executor callbackExecutor;
public MyCallAdapter(Type responseType, Executor callbackExecutor)
this.responseType = responseType;
this.callbackExecutor = callbackExecutor;
@Override
public Type responseType()
return null;
@Override
public MyCall<T> adapt(Call<T> call)
return new MyCallImpl<>(call, callbackExecutor);
public class MyCallImpl<T> implements MyCall<T>
private final Call<T> call;
private final Executor callbackExecutor;
MyCallImpl(Call<T> call, Executor callbackExecutor)
this.call = call;
this.callbackExecutor = callbackExecutor;
@Override
public void enqueue(MyCallback<T> callback)
call.enqueue(new Callback<T>()
@Override
public void onResponse(Call<T> call, Response<T> response)
/* This is the problem. it will seems wrap to ApiResponse<ApiResponse<Result>>> because T is <ApiResponse<Result>>.
*/
callback.onResult(new ApiResponse<>(response));
@Override
public void onFailure(Call<T> call, Throwable t)
/** This one is also the issue. */
callback.onResult(new ApiResponse<>(t));
);
@Override
public void cancel()
call.cancel();
@Override
public MyCall<T> clone()
return new MyCallImpl<>(call.clone(), callbackExecutor);
public interface MyCallback<T>
void onResult(ApiResponse<T> response);
以上代码在处理双参数泛型类型时存在问题。我不知道如何处理它。
同样运行这段代码也是崩溃
Caused by: java.lang.NullPointerException: type == null
at retrofit2.Utils.checkNotNull(Utils.java:286)
at retrofit2.Retrofit.nextResponseBodyConverter(Retrofit.java:324)
at retrofit2.Retrofit.responseBodyConverter(Retrofit.java:313)
at retrofit2.ServiceMethod$Builder.createResponseConverter(ServiceMethod.java:736)
at retrofit2.ServiceMethod$Builder.build(ServiceMethod.java:169)
有人可以帮助如何让MyCall<ApiResponse<Result>>
用MyCallback<ApiResponse<Result>>
调用入队吗?结果是用Gson转换器解析json数据内容。
public class MyCallAdapter<T> implements CallAdapter<T, MyCall<ApiResponse<T>>>
public MyCall<ApiResponse<T>> adapt(Call<T> call)
/* This one will have the problem after changing MyCall<T> to MyCall<ApiResponse<T>>, Parameterized type mismatch.*/
return new MyCallImpl<>(call, callbackExecutor);
有人可以帮我指出问题吗?
【问题讨论】:
@Override public Type responseType() return null;
在该方法中返回 responseType
@Rahul,非常感谢您指出。我现在修好了。
不客气
【参考方案1】:
修改 MyCallAdapter、MyCallback 和 MyCallImpl。 @Rahul 指出响应类型,现在一切正常。
public class MyCallAdapter<T> implements CallAdapter<T, MyCall<ApiResponse<T>>>
private final Type responseType;
private final Executor callbackExecutor;
public MyCallAdapter(Type responseType, Executor callbackExecutor)
this.responseType = responseType;
this.callbackExecutor = callbackExecutor;
@Override
public Type responseType()
return responseType;
@Override
public MyCall<ApiResponse<T>> adapt(Call<T> call)
return new MyCallImpl<>(call, callbackExecutor);
public interface MyCallback<T>
void onResult(T response);
public class MyCallImpl<T> implements MyCall<ApiResponse<T>>
private final Call<T> call;
private final Executor callbackExecutor;
MyCallImpl(Call<T> call, Executor callbackExecutor)
this.call = call;
this.callbackExecutor = callbackExecutor;
@Override
public void enqueue(MyCallback<ApiResponse<T>> callback)
call.enqueue(new Callback<T>()
@Override
public void onResponse(Call<T> call, Response<T> response)
callback.onResult(new ApiResponse<>(response));
@Override
public void onFailure(Call<T> call, Throwable t)
callback.onResult(new ApiResponse<>(t));
);
@Override
public void cancel()
call.cancel();
@Override
public MyCall<ApiResponse<T>> clone()
return new MyCallImpl<>(call.clone(), callbackExecutor);
以上是正确的实现。是的。
【讨论】:
我们如何调用才能使 api 命中?以上是关于自定义呼叫适配器改造中的通用类型的主要内容,如果未能解决你的问题,请参考以下文章
Android 屏幕适配屏幕适配通用解决方案 ⑤ ( 自定义组件解决方案 | 自定义 ViewGroup 组件 onMeasure 方法中计算每个子组件坐标数据 | 自定义组件完整代码 )
EditText.SetText() 在自定义适配器中更改我的软键盘输入类型
Android 屏幕适配屏幕适配通用解决方案 ③ ( 自定义组件解决方案 | 获取设备状态栏高度 | 获取设备屏幕数据 )
Android 屏幕适配屏幕适配通用解决方案 ③ ( 自定义组件解决方案 | 获取设备状态栏高度 | 获取设备屏幕数据 )