前言
最近在学习和整理安卓框架架构知识,看到了Retrofit这一块,想想这块的内容还是前两年接触的,但是一直只是停留在能够使用Retrofit完成任务开发的应用层,对他的核心业务逻辑没有功夫细看,现在整好手里的工作也不忙,在梳理自己的知识体系,就想把这部分内容深入了解一下,从源码角度看看他到底都做了哪些事,关于适配器,和回调工厂,gson处理和数据转换这部分,我还没分析,所以先把整体的实现网络请求的核心逻辑部分梳理一下, 希望大家能看的懂,一起学习,共同进步。接下里会整理关于适配器工厂,和数据转换部分的内容。
1. Retrofit如何应用
1.1 添加依赖
implementation 'com.squareup.retrofit2:retrofit:2.1.0'
1.2 使用方式
接口使用方式`在这里插入代码片`
private final static String IP = "144.34.161.97";
private final static String KEY = "aa205eeb45aa76c6afe3c52151b52160";
private final static String BASE_URL = "http://apis.juhe.cn/";
interface HOST {
@GET("ip/ipNew")
Call get(@Query("ip") String ip, @Query("key") String key);
@POST("ip/ipNew")
Call post(@Field("ip") String ip, @Field("key") String key);
}
1.3 开发测试使用
@Test
public void testRetrofit() throws Exception {
//1.通过builder 模式创建Retrofit的实例并生成build
Retrofit retrofit = new Retrofit.Builder()
.getBaseUrl(BASE_URL)
.build();
//2. 根据接口的class类通过create创建相应的操作类Class
HOST host = retrofit.create(HOST.class);
//3.RETROFIT GET同步请求
{
Call call = host.get(IP, KEY);
Response response = call.execute();
if (response != null && response.body() != null) {
System.out.println("Retrofit GET同步请求 >>>" + response.body().string());
}
}
//3.Retrofit Post同步请求
Call call = host.post(IP, KEY);
Response response = call.execute();
if (response != null && response.body() != null) {
System.out.println("Retrofit POSt同步请求 >>>" + response.body().string());
}
}
上面的代码便是Retrofit网络请求的全部代码了,接下来我们看看打印结果:
Retrofit GET同步请求 >>>{
"resultcode":"200","reason":"查询成功","result":{
"Country":"美国","Province":"加利福尼亚","City":"","Isp":""},"error_code":0}
Retrofit POSt同步请求 >>>{
"resultcode":"200","reason":"查询成功","result":{
"Country":"美国","Province":"加利福尼亚","City":"","Isp":""},"error_code":0}
2. Retrofit的分析
我们先从源码入手分析:
我们可以看到Retrofit的整体体思想是以Builder建造者模式设计的,那么我们就从Builder开始分析 为了简化代码,便于挑出retrofit的整体思想框架所以我们先根据他的源码,进行简化处理一下,处理后的代码如下
public class Retrofit {
private HttpUrl mBaseUrl;
private Call.Factory mFactory;
private final Map<Method, ServiceMethod> mServiceMethodCache = new ConcurrentHashMap<>();
Retrofit(Builder builder) {
this.mBaseUrl = builder.mBaseUrl;
this.mFactory = builder.mFactory;
}
//提供对外的API调用
public Call.Factory callFactory() {
return mFactory;
}
public HttpUrl baseUrl() {
return mBaseUrl;
}
/***
* 使用动态代理的方式创建定义的接口类
* @param service
* @param <T>
* @return
*/
@SuppressWarnings("unchecked")
public <T> T create(Class<T> service) {
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[]{
service}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
ServiceMethod serverMethod = loadServiceMethod(method);
return new OkHttpCall(serverMethod, args);
}
});
}
/***
* 加载代理服务的方法
* @param method (get两次避免第二次从缓存中拿到的为空 ,因为第一次new 的时候执行了同步)
* @return
*/
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result = mServiceMethodCache.get(method);
if (result != null) return result;
synchronized (mServiceMethodCache) {
result = mServiceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
mServiceMethodCache.put(method, result);
}
}
return result;
}
public static final class Builder {
private HttpUrl mBaseUrl;
private Call.Factory mFactory;
public Builder getBaseUrl(String baseUrl) {
if (baseUrl.isEmpty()) {
throw new NullPointerException("baseUrl == null");
}
this.mBaseUrl = HttpUrl.parse(baseUrl);
return this;
}
public Builder callFactory(Call.Factory factory) {
this.mFactory = factory;
return this;
}
public Retrofit build() {
if (mFactory == null) {
mFactory = new OkHttpClient();
}
return new Retrofit(this);
}
}
}
我们看到Retrofit主要定义了三个属性(因为这里我们先不考虑线程调度和适配器模式)
private HttpUrl mBaseUrl;
private Call.Factory mFactory;
private final Map<Method, ServiceMethod> mServiceMethodCache = new ConcurrentHashMap<>();
第一个是HttpUrl 主要是处理我们的请求路径,也就是最前面的路径类似于:http://www.xxx.com 第二个是一个Factory,实际上它是okhttp的 call的接口。里面定义了call newCall(Request request),因为Retrofit的底层实际上是用的是okhttp,他相当于对okhttp做了进一步的封装,更具有拓展性。 第三个是一个ServiceMethod的Map集合,涉及到自定义注解,这个我们之后会讲到 这是一个重点。
对于Builder 我们就不多做解释了他就是一个建造者模式的常用类,我们需要在这里对方法属性进行赋值并且返回Builder,并通过Build方法new 一个Retrofit(this),传入builder ,因为在retrofit中我们需要使用这个builder如下:
Retrofit(Builder builder) {
this.mBaseUrl = builder.mBaseUrl;
this.mFactory = builder.mFactory;
}
这里不给他设置访问修饰符,是为了不可以被其他类实例化,有的人觉得那可以使用单例,这个不能使用单例,可能会造成内存泄漏.
2.2 我们可以看到在一个Retrofit中有这样一个方法
/***
* 使用动态代理的方式创建定义的接口类
* @param service
* @param <T>
* @return
*/
@SuppressWarnings("unchecked")
public <T> T create(Class<T> service) {
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[]{
service}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
ServiceMethod serverMethod = loadServiceMethod(method);
return new OkHttpCall(serverMethod, args