Android进阶必学retrofit源码解析

源码的分析将从基本的使用方法入手,分析retrofit的实现方案,以及其中涉及到的一些有趣的技巧。

‘Android技术交流群653583088,欢迎大家加入交流,畅谈!本群有免费学习资料视频’并且免费分享retrofit源码解析视频

简单使用

定义HTTP API

public interface GitHubService {
@GET(“users/{user}/repos”)
Call<List> listRepos(@Path(“user”) String user);
}

创建Retrofit并生成API的实现

Retrofit retrofit = new Retrofit.Builder()
.baseUrl(“https://api.github.com/”)
.build();
GitHubService service = retrofit.create(GitHubService.class);

调用API方法,生成Call

Call<List> repos = service.listRepos(“octocat”);

Retrofit的创建

retrofit实例的创建,使用了builder模式,从下面的源码中可以看出

public static final class Builder {
Builder(Platform platform) {
this.platform = platform;
converterFactories.add(new BuiltInConverters());
}
public Builder() {
// Platform.get()方法可以用于判断当前的环境
this(Platform.get());
}
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, “baseUrl == null”);
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
if (httpUrl == null) {
throw new IllegalArgumentException("Illegal URL: " + baseUrl);
}
return baseUrl(httpUrl);
}

public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException(“Base URL required.”);
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();// 新建Client,留到之后newCall什么的
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
}

retrofit.create

好玩的地方开始了,我们先来看看这个方法

public T create(final Class service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
// 动态代理,啦啦啦
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
// platform 可以分辨出你是在android,还是java8,又或者别的
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
// 这里的invoke,Object方法都走这里,比如equals、toString、hashCode什么的
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// java8默认方法,1.8的新特性
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
// 这里是核心代码了
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}

可以看出创建API使用了动态代理,根据接口动态生成的代理类,将接口的都转发给了负责连接代理类和委托类的InvocationHandler实例,接口方法也都通过其invoke方法来处理。
在invoke方法中,首先会通过Platform.get()方法判断出当前代码的执行环境,之后会先把Object和Java8的默认方法进行一个处理,也是在进行后续处理之前进行去噪。其中的关键代码其实就是最后三句,这也是这篇文章将要分析的

创建ServiceMethod

erviceMethod<?, ?> loadServiceMethod(Method method) {
// 从缓存里面取出,如果有的话,直接返回好了
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
// 为null的话,解析方法的注解和返回类型、参数的注解he参数类型,新建一个ServiceMethod
result = new ServiceMethod.Builder<>(this, method).build();// ->
// 新建的ServiceMethod加到缓存列表里面
serviceMethodCache.put(method, result);
}
}
return result;
}

注解的解析

CallAdapter和Converter等到后面再分析,这里先看看parseMethodAnnotation(annotation),功能和其名字一样,其对方法注解进行了解析

/**

  • 解析方法注解,呜啦啦
  • 通过判断注解类型来解析
  • @param annotation
    */
    private void parseMethodAnnotation(Annotation annotation) {
    if (annotation instanceof DELETE) {
    parseHttpMethodAndPath(“DELETE”, ((DELETE) annotation).value(), false);
    } else if (annotation instanceof GET) {
    parseHttpMethodAndPath(“GET”, ((GET) annotation).value(), false);
    }
    // 其他的一些方法注解的解析

    }
    private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
    if (this.httpMethod != null) {// 已经赋值过了
    throw methodError(“Only one HTTP method is allowed. Found: %s and %s.”,
    this.httpMethod, httpMethod);
    }
    this.httpMethod = httpMethod;
    this.hasBody = hasBody;
    // value为设置注解方法时候,设置的值,官方例子中的users/{user}/repos or user
    if (value.isEmpty()) {
    return;
    }
    // 查询条件的一些判断

    this.relativeUrl = value;
    this.relativeUrlParamNames = parsePathParameters(value);
    }
    `

在解析注解时,先通过instanceof判断出注解的类型,之后调用parseHttpMethodAndPath方法解析注解参数值,并设置httpMethod、relativeUrl、relativeUrlParamNames等属性。

上面说了API中方法注解的解析,现在来看看方法参数注解的解析,这是通过调用parseParameterAnnotation方法生成ParameterHandler实例来实现的,代码比较多,这里挑选@Query来看看。

else if (annotation instanceof Query) {
Query query = (Query) annotation;
String name = query.value();
boolean encoded = query.encoded();
Class<?> rawParameterType = Utils.getRawType(type);// 返回基础的类
gotQuery = true;
// 可以迭代,Collection
if (Iterable.class.isAssignableFrom(rawParameterType)) {
if (!(type instanceof ParameterizedType)) {
throw parameterError(p, rawParameterType.getSimpleName()

  • " must include generic type (e.g., "
  • rawParameterType.getSimpleName()
  • “)”);
    }
    ParameterizedType parameterizedType = (ParameterizedType) type;
    Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);// 返回基本类型
    Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations); return new ParameterHandler.Query<>(name, converter, encoded).iterable(); } else if (rawParameterType.isArray()) {// Array Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());// 如果是基本类型,自动装箱
    Converter<?, String> converter =
    retrofit.stringConverter(arrayComponentType, annotations);
    return new ParameterHandler.Query<>(name, converter, encoded).array();
    } else {// Other
    Converter<?, String> converter =
    retrofit.stringConverter(type, annotations);
    return new ParameterHandler.Query<>(name, converter, encoded);
    }

在@Query中,将分成Collection、array、other三种情况处理参数,之后根据这些参数,调用ParameterHandler中的Query静态类,创建出一个ParameterHandler实例。这样循环直到解析了所有的参数注解,组合成为全局变量parameterHandlers,之后构建请求时会用到

OkHttpCall

ServiceMethod创建完成之后,我们来看看下一行代码中的OkHttpCall类,里面的包含了请求的执行和响应处理,我们来看看异步请求的做法

OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
@Override public void enqueue(final Callback callback) {
checkNotNull(callback, “callback == null”);
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException(“Already executed.”);
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
call = rawCall = createRawCall();// 创建OkHttp3.Call
} catch (Throwable t) {
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response response;
try {
response = parseResponse(rawResponse);// ->
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callSuccess(Response response) {
try {
callback.onResponse(OkHttpCall.this, response);
先自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以扫码领取!!!!

小结

有了这么多优秀的开发工具,可以做出更高质量的Android应用。

当然了,“打铁还需自身硬”,想要写出优秀的代码,最重要的一点还是自身的技术水平,不然用再好的工具也不能发挥出它的全部实力。

在这里我也分享一份大佬自己收录整理的Android学习PDF+架构视频+面试文档+源码笔记,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这些都是我闲暇还会反复翻阅的精品资料。在脑图中,每个知识点专题都配有相对应的实战项目,可以有效的帮助大家掌握知识点。

总之也是在这里帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可免费领取!

oid学习PDF+架构视频+面试文档+源码笔记**,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这些都是我闲暇还会反复翻阅的精品资料。在脑图中,每个知识点专题都配有相对应的实战项目,可以有效的帮助大家掌握知识点。

总之也是在这里帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可免费领取!

  • 14
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值