Retrofit源码分析
来源:互联网 发布:lol域名注册 编辑:程序博客网 时间:2024/05/23 01:11
———-继续,这篇分析Retrofit的源码。(真是太懒了)
首先看一下官网的介绍,(官网 在此),官网给的描述是 A type-safe HTTP client for Android and Java,其实也就是对okhttp再次进行了封装,使得开发者更方便的使用网络请求。基本使用如下:
1,先创建一个接口,里面定义了请求方式,地址,返回数据类型,参数。
public interface GitHubService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); @GET("users/{user}/repos") Obeserble<List<Repo>> listRepos(@Path("user") String user);}
2,生成一个Retrofit实例,然后调用create()方法,传入刚才创建的GitHubService 类名。
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .build();GitHubService service = retrofit.create(GitHubService.class);
3,直接从接口拿到一个Call,当然,这个类型可以是其他类型的。
Call<List<Repo>> repos = service.listRepos("octocat");
基本用法请自行了解,这里我们主要分析源码。
创建Retrofit 实例是一个Builder模式,没什么好说的,需要注意的一点是, 这创建的时间调用了unmodifiableList(),这是Collections类的一个方法,
public static <T> List<T> unmodifiableList(List<? extends T> list) { return (list instanceof RandomAccess ? new UnmodifiableRandomAccessList<>(list) : new UnmodifiableList<>(list)); }
瞄一眼方法描述,Returns an unmodifiable view of the specified list. This method allows modules to provide users with “read-only” access to internal lists. 开头两句是这么写的, 就是说返回一个不可更改的List对象,可以保护创建的对象中的数据只读, 不能更改。之前没遇到过,记录下。
接下来重点(敲黑板!!!)
public <T> T create(final Class<T> service) { Utils.validateServiceInterface(service); if (validateEagerly) { eagerlyValidateMethods(service); } return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { 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. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall); } }); }
看到了一个返回Proxy,知道这是代理的意思,其实这里用到了动态代理的方法,(有关 动态代理和静态代理的 区别请看 此)。
这里解释下InvocationHandler 中回调invoke方法的参数 。
- Object proxy: 代理对象,不关心这个
- Method method:调用的方法,就是listRepos方法
- Object… args:方法的参数,就是”octocat”
可以知道,
if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); }if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); }
都不会执行。
那么接下来我们首先看 loadServiceMethod(method) 方法 。
ServiceMethod<?, ?> loadServiceMethod(Method method) { ServiceMethod<?, ?> result = serviceMethodCache.get(method); if (result != null) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = new ServiceMethod.Builder<>(this, method).build(); serviceMethodCache.put(method, result); } } return result; }
这里有Map去缓存ServiceMethod对象,如果有则直接返回,没有就去创建 。
我们看ServiceMethod的构造函数。也是使用了Builder模式 ,
public ServiceMethod build() { callAdapter = createCallAdapter(); responseType = callAdapter.responseType(); responseConverter = createResponseConverter(); int parameterCount = parameterAnnotationsArray.length; parameterHandlers = new ParameterHandler<?>[parameterCount]; for (int p = 0; p < parameterCount; p++) { Type parameterType = parameterTypes[p]; if (Utils.hasUnresolvableType(parameterType)) { throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s", parameterType); } Annotation[] parameterAnnotations = parameterAnnotationsArray[p]; if (parameterAnnotations == null) { throw parameterError(p, "No Retrofit annotation found."); } parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations); } return new ServiceMethod<>(this); }
这里删除一些检查的代码,看主要的。
最后调用build();会创建一些初始对象。每一个参数都都会封装到一个ParameterHandler里。
然后new 了一个okhttpCall ,直接调用 serviceMethod.callAdapter.adapt(okHttpCall); 这里的serviceMethod.callAdapte , 就是之前serviceMethod.Builder 中调用createCallAdapter()返回赋值给serviceMethod的成员对象。
这里比较有意思了,
private CallAdapter<T, R> createCallAdapter() { Type returnType = method.getGenericReturnType(); if (Utils.hasUnresolvableType(returnType)) { throw methodError( "Method return type must not include a type variable or wildcard: %s", returnType); } if (returnType == void.class) { throw methodError("Service methods cannot return void."); } Annotation[] annotations = method.getAnnotations(); try { //noinspection unchecked return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(e, "Unable to create call adapter for %s", returnType); } }
看retrofit.callAdapter ,返回到了Retrofit中, 在nextCallAdapter 中有
int start = adapterFactories.indexOf(skipPast) + 1; for (int i = start, count = adapterFactories.size(); i < count; i++) { CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this); if (adapter != null) { return adapter; } }
遍历adapterFactories,依据刚才在GitHubService 中每个方法的返回值,对应着一个Factory,比如,在Retrofit中Builder的时候默认添加了一个
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
,也就是说当你在初始化Retrofit的时候不去addCallAdapterFactory();默认的返回类型必须是Call。返回其它的类型,在遍历的时候找不到对应的Factory, 会抛异常。
回到serviceMethod.callAdapter.adapt(okHttpCall);
这里的callAdapter 其实默认就是一个ExecutorCallAdapterFactory.get()返回的值 , 我们进入这个类。
@Override public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != Call.class) { return null; } final Type responseType = Utils.getCallResponseType(returnType); return new CallAdapter<Object, Call<?>>() { @Override public Type responseType() { return responseType; } @Override public Call<Object> adapt(Call<Object> call) { return new ExecutorCallbackCall<>(callbackExecutor, call); } }; }
看Call方法
@Override public Call<Object> adapt(Call<Object> call) { return new ExecutorCallbackCall<>(callbackExecutor, call); }
当我们拿到一个Call 时, 可以去enqueue()(异步),或execute();那么这个Call呢, 其实就是OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
这里的Call了。OkHttpCall我觉得可以当作是适配器模式,可也以做包装设计模式 。
这里面的代码比较简单,直接生成一个Okhttp包的Call,再去调用。
至此,Retrofit 的源码已经分析完,我们只是粗略的过了一下流程,整个Retrofit用到了很多种设计模式,这个我们得好好消化一下。完
- Retrofit源码分析
- Retrofit源码分析
- Retrofit源码分析
- Retrofit源码简要分析
- Retrofit源码分析1
- Retrofit源码分析
- Retrofit 源码分析
- Retrofit源码分析
- Retrofit源码分析
- Retrofit 2.0源码分析
- Retrofit 源码分析
- Retrofit源码分析
- Retrofit的源码分析
- Retrofit 源码分析
- Retrofit 源码分析流程
- Retrofit源码分析
- Retrofit 源码简单分析
- Retrofit源码分析-前
- 一篇关于mysql比较好的文章
- 95-PING 命令实现
- '-[__NSArrayM enqueue:]: unrecognized selector sent to instance 0x60000024ef40'
- jquery load加载页面无法使用原页面js
- NodeJS相关小问题
- Retrofit源码分析
- Kotlin干货集中营
- spring系列之@Configuration注解、@Bean注解以及自动扫描注解@componentScan
- Maven打jar实现lib 配置 和打的jar分离
- Linux(七)
- 代理模式(Proxy)
- 外观模式(Facade)
- hibernate中实体相关内容总结
- 解决Windows版Git(SourceTree)出现templates not found的问题