从OkHttp到Retrofit
简单使用
class RetrofitActivity : AppCompatActivity() {
companion object {
const val SERVER = "https://www.xxx.com/"
}
var disposable:Disposable? = null;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_retrofit)
val retrofit = Retrofit.Builder()
.baseUrl(SERVER)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
disposable = retrofit.create(TestApi::class.java).getIcons(1).subscribe(
{
Log.d("api", it.isSuccessful.toString())
}, {
Log.d("api", it.toString())
})
}
override fun onStop() {
super.onStop()
disposable.dispose()
}
}
//RESTFUL 风格接口
interface TestApi {
@GET("/test/icon")
fun getIcons(
@Query("icon_id") icon_id: Long
): Observable<Response<IconBean>>
}
class IconBean{}
实现原理
Retrofit的代码逻辑比较复杂,但是实际上Retrofit的主要功能就是给OkHttp做一层封装,这里我把主要流程进行了总结,简单来说当调用Retrofit.create(TestApi.classjava)
方法之后,Retrofit首先会判断TestApi这个类是否符合条件,如果开启了严格检查的话,还会提前加载HttpServiceMethod。
//Retrofit.java
public <T> T create(final Class<T> service) {
//验证
validateServiceInterface(service);
return (T)
//动态代理
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
//判断android和jvm平台及其版本
private final Platform platform = Platform.get();
@Override
public Object invoke(Object proxy, Method method, Object[] args){
//如果是静态方法则直接执行
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//isDefaultMethod:是否是默认方法
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
private void validateServiceInterface(Class<?> service) {
//判断是不是接口,不是就抛出异常
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
//判断存不存在泛型,存在则抛出异常
Deque<Class<?>> check = new ArrayDeque<>(1);
check.add(service);
while (!check.isEmpty()) {
Class<?> candidate = check.removeFirst();
if (candidate.getTypeParameters().length != 0) {
StringBuilder message =
new StringBuilder("Type parameters are unsupported on ").append(candidate.getName());
if (candidate != service) {
message.append(" which is an interface of ").append(service.getName());
}
throw new IllegalArgumentException(message.toString());
}
Collections.addAll(check, candidate.getInterfaces());
}
//提前加载
if (validateEagerly) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
loadServiceMethod(method);
}
}
}
}
loadServiceMethod
当检查完成之后,Retrofit就会创建出一个代理类,因此调用retrofit.create(TestApi::class.java).getIcons(1)
事实上是调用了代理类的invoke方法,这个invoke方法会首先根据注解进行解析,添加参数,生成一个okHttp的Call请求,然后通过适配器模式将Call的返回结果进行适配。例如我希望使用RxJava的Observable作为返回类型,那么这里可以使用RxJavaCallAdapterFactory
将OkHttp返回的Call<T>
类型转换为Observable<T>
。
基于这个流程,来阅读一下代码。
ServiceMethod<?> loadServiceMethod(Method method) {
//判断是否有缓存
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//没有缓存的话根据注解解析一个
//这里的返回是一个HttpServiceMethod,里面包含了一个适配好的call
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
//ServiceMethod.java
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
//检查:articleList方法返回类型不能用通配符和void...
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
可以看到ServiceMethod中首先创建了一个RequestFactory,RequestFactory的作用是根据注解来
//RequestFactory.java
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
class Builder {
RequestFactory build() {
//解析请求类型,methodAnnotations是method中的注解,通过getAnnotations()获取
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//...
//解析参数注解如Path,parameterAnnotationsArray是参数注解数组
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
//...
return new RequestFactory(this);
}
}
从这里可以看出当build方法调用之后,事实上RequestFactory对传入的方法完成了解析,并且把解析的结果保存在自己成员变量中。
//HttpServiceMethod.java
//ResponseT响应类型如WanArticleBean,ReturnT返回类型如Call
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
//...
Annotation[] annotations = method.getAnnotations();
//遍历找到合适的适配器
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
//得到响应类型
Type responseType = callAdapter.responseType();
//根据返回类型找到合适的转换器
//最终又会回调到retrofit里面的callAdapterFactories
//callAdapterFactories在一开始builder时候传入
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
//父类HttpServiceMethod中的实现。
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
}
结合之前的说明,可以看到当找到和是的适配器之后,loadServiceMethod会返回一个CallAdapted,并且当调用invoke方法时候,会根据CallAdapted内部的callAdapter,将Call转化为适配类型。
callAdapter又是从retrofit的callAdapterFactories中遍历得到,所以这里再回过来看看retrofit.builder()方法。
//Retrofit.Builder.java
public Retrofit build() {
Executor callbackExecutor = this.callbackExecutor;
//如果没设置线程池,则给android平台设置一个默认的MainThreadExecutor(用Handler将回调切回主线程)
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
//添加默认的DefaultCallAdapterFactory
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
}
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
return hasJava8Types
//默认的只有两个,如果需要使用其他的AdapterFactory需要在创建的时候传入
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
Converter
Converter的作用就是转化各种参数类型。
interface WanApi {
//Long cur 当前时间
@GET("article/list/{page}/json")
Call<WanArticleBean> articleList(@Path("page") int page, @Query("cur") Long cur);
}
class TimeConverter implements Converter<Long, String> {
private SimpleDateFormat mFormat = new SimpleDateFormat("yyyy-MM-dd-HHmmss");
@Override
public String convert(Long value) throws IOException {
if (value > 1_000_000_000_000L) {//毫秒,不是很严谨 - -
return mFormat.format(new Date(value));
}
return String.valueOf(value);
}
}
class TimeConverterFactory extends Converter.Factory {
@Override
public Converter<?, String> stringConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
if (type == Long.class) {
//使用自定义TimeConverter
return new TimeConverter();
}
return super.stringConverter(type, annotations, retrofit);
}
public static Converter.Factory create() {
return new TimeConverterFactory();
}
}
//addConverterFactory(TimeConverterFactory.create())