本篇为个人理解心得 多有不详细 还请移步:
https://www.jianshu.com/p/0c055ad46b6c
从retrofit的简单使用开始
retrofit使用步骤:
1.创建Retrofit实例
2.创建 网络请求接口实例 并 配置网络请求参数
3.发送网络请求
4.处理服务器返回的数据
一.创建retrofit实例
Retrofit retrofit = new Retrofit//第一步
.Builder()//第二步
.baseUrl("http://apis.juhe.cn/")//第三步
.addConverterFactory(GsonConverterFactory.create())//第四步
.build();//第五步
这里可以看到:Retrofit实例是使用建造者模式通过Builder
类进行创建的
分为五个步骤逐步分析:
第一步 new Retrofit
//Retrofit类
public final class Retrofit {
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
//网络请求配置对象 存储网络请求相关配置(请求方法,数据转换器,baseurl等)
final okhttp3.Call.Factory callFactory;
//网络请求器工厂:用于生产网络请求器 默认使用okhttp
final HttpUrl baseUrl;//服务器地址baseurl
final List<Converter.Factory> converterFactories;
//数据转换器工厂集合 (允许多个不同数据转换器工厂放入其中)
//数据转换器工厂用于生产数据转换器 converter
final List<CallAdapter.Factory> callAdapterFactories;
// 网络请求适配器工厂的集合(允许多个不同网络请求适配器工厂放入其中)
// 网络请求适配器工厂作用:生产网络请求适配器(CallAdapter)
//将默认的网络请求器(OkhttpCall)转化为适合不同平台来调用的网络请求执行器形式
final @Nullable Executor callbackExecutor;
final boolean validateEagerly;
//retrofit构造函数
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,
@Nullable Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
//省略的代码
......
}
建立好Retrofit对象的一个标准:
- 包含所有网络请求信息的对象
serviceMethod
- 网络请求的url地址
baseUrl
- 网络请求工厂
callFactory
- 网络请求适配器工厂的集合
callAdapterFactories
- 数据转换器工厂的集合
converterFactories
- 回调方法执行器
callbackExecutor
第二步 .Builder()
Retrofit建造者
public static final class Builder {
//Builder类的成员变量与Retrofit类的成员变量是对应的
//Retrofit类的成员变量基本上是通过Builder类进行配置
private final Platform platform;
private @Nullable okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private final List<Converter.Factory> converterFactories = new ArrayList<>();
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
private @Nullable Executor callbackExecutor;
private boolean validateEagerly;
Builder(Platform platform) {//有参构造方法
this.platform = platform;
}
//采用Builder的无参构造方法
public Builder() {
//this调用自己已有的上边的有参构造方法
//通过调用Platform.get()传入了Platform对象
this(Platform.get());
}
//省略的代码
......
}
以上可以看到builder的无参构造方法中调用了有参构造方法
Builder(Platform platform)
并通过Platform.get()
传入需要的Platform
对象
紧接着看Platform.get()
代码:
class Platform {
//findPlatform()赋值到静态变量PLATFORM
private static final Platform PLATFORM = findPlatform();
static Platform get() {
// 返回静态变量PLATFORM,即findPlatform()
return PLATFORM;
}
//省略的代码
......
}
以上可以看到在Platform
中,首先通过findPlatform()
赋值静态变量PLATFORM
,然后get()
方法返回PLATFORM
接下来看看findPlatform()
方法
private static Platform findPlatform() {
try {
//查找并加载指定类android.os.Build
Class.forName("android.os.Build");
//// 如果是Android平台,就创建并返回一个Android对象
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
//这里添加对java平台的支持 同上
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
// 从上面看出此版本Retrofit支持2个平台:Android平台、Java平台
// 最后返回一个Platform对象给Builder的有参构造方法public Builder(Platform platform)
return new Platform();
}
以上我们可以看到Builder
指定了运行平台,这里主要看指定了Android
平台后的操作,通过return new Android()
创建并返回了一个Android对象
接下来看看Android
类的源代码:
static class Android extends Platform {
ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory
@Override public Executor defaultCallbackExecutor() {
// 返回一个默认的回调方法执行器
// 该执行器作用:切换线程(子->>主线程),并在主线程(UI线程)中执行回调方法
return new MainThreadExecutor();
}
// 创建默认的网络请求适配器工厂
// 该默认工厂生产的 adapter 会使得Call在异步调用时在指定的 Executor 上执行回调
// 在Retrofit中提供了四种CallAdapterFactory:
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
// 获取与Android 主线程绑定的Handler
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
// 该Handler是上面获取的与Android 主线程绑定的Handler
// 在UI线程进行对网络请求返回数据处理等操作。
handler.post(r);
}
}
}
总结一下,Builder
设置了默认的
- 平台类型对象:
Android
- 网络请求适配器工厂:
CallAdapterFactory
- 数据转换器工厂:
converterFactory
- 回调执行器:
callbackExecutor
这里Builder只是设置默认值,并没有真正配置到具体的Retrofit类的成员变量中
第三步.baseUrl("http://apis.juhe.cn/")
配置baseUrl
看baseUrl(String baseUrl)
源代码
public Builder baseUrl(String baseUrl) {
//首先检查是否为空
checkNotNull(baseUrl, "baseUrl == null");
// 把String类型的url参数转化为适合OKhttp的HttpUrl类型
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
if (httpUrl == null) {
throw new IllegalArgumentException("Illegal URL: " + baseUrl);
}
//最终返回重载的baseUrl(HttpUrl baseUrl)参数类型为httpUrl
return baseUrl(httpUrl);
}
以上我们可以看到baseUrl(String baseUrl)
对传入的String型的baseUrl进行了非空判断,并且将baseUrl
类型转换到适合OKhttp的HttpUrl类型,并返回重载的baseUrl(HttpUrl baseUrl)
下面看baseUrl(HttpUrl baseUrl)
源码
public Builder baseUrl(HttpUrl baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
//把URL参数分割成几个路径碎片
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
// 检测最后一个碎片来检查URL参数是不是以"/"结尾
// 不是就抛出异常
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
总结:baseUrl()用于配置Retrofit类的网络请求url地址,其内部对baseUrl进行了简单处理和判断,规定了baseUrl必须以 / 结尾
第四步.addConverterFactory(GsonConverterFactory.create())
由里到外,先看GsonConverterFactory.creat()
源码
public final class GsonConverterFactory extends Converter.Factory {
//首先是调用了这个无参的create()
public static GsonConverterFactory create() {
// 创建一个Gson对象 传给create(Gson gson) 并返回
return create(new Gson());
}
@SuppressWarnings("ConstantConditions") // Guarding public API nullability.
public static GsonConverterFactory create(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
// 创建了一个含有Gson对象实例的GsonConverterFactory 传给构造函数GsonConverterFactory(Gson gson) 并返回
return new GsonConverterFactory(gson);
}
private final Gson gson;
//最终返回的是以下构造函数生成的GsonConverterFactory对象
private GsonConverterFactory(Gson gson) {
this.gson = gson;
}
以上我们可以看到GsonConverterFactory.creat()
是创建了一个含有Gson对象实例的GsonConverterFactory
,并返回给addConverterFactory()
接下来看addConverterFactory()
// 将上面创建的GsonConverterFactory放入到 converterFactories数组
// 在第二步放入一个内置的数据转换器工厂BuiltInConverters()后又加入了一个GsonConverterFactory
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
总结:第四部创建了一个含有Gson对象实例的GsonConverterFactory
并放入到数据转换器工厂converterFactories
里
在数据转换器工厂集合中加入GsonConverterFactory
是用于序列化 Java 对象为 JSON 字符串,或反序列化 JSON 字符串成 Java 对象。
使用到了谷歌的Gson框架来进行数据的转换,当服务器返回的数据是json格式的时候,可以通过这个框架来转换为实体对象。
我们配置的Retrofit默认使用Gson进行解析,若使用其他解析方式(XML或Protocobuf),也可通过自定义数据解析器来实现
注:Gson不要求本地实体类和返回的json所以数据字段完全匹配
实体类没有的字段但服务器中有返回,该字段无法被使用
实体类中有的字段但服务器没有返回,该字段为空
(此时直接调用没有返回的字段会出前空指针错误)
第五步.build()
看源码
public Retrofit build() {
//如果baseUrl 是空,抛出异常
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//配置网络请求执行器(callFactory )
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
// 如果没指定,则默认使用okhttp
// 这里可以看到Retrofit默认使用okhttp进行网络请求
callFactory = new OkHttpClient();
}
//配置回调方法执行器(callbackExecutor)
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
// 如果没指定,则默认使用Platform检测环境时的默认callbackExecutor
// 即Android默认的callbackExecutor
callbackExecutor = platform.defaultCallbackExecutor();
}
//配置网络请求适配器工厂(CallAdapterFactory)
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
//// 向该集合中添加了第二步中创建的CallAdapter.Factory请求适配器
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
//配置数据转换器工厂(converterFactory)
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
// 在第二步中已经添加了内置的数据转换器 BuiltInConverters()(添加到集合器的第一位)
// 在第四步中又插入了一个Gson的转换器 GsonConverterFactory(添加到集合器的第二位)
//1获取合适的网络请求适配器和数据转换器都是从adapterFactories和converterFactories集合的首位开始
// 因此集合中的工厂位置越靠前就拥有越高的使用权重
// 最终返回一个Retrofit的对象,并传入上述已经配置好的成员变量
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
总结:在最后一步中,通过前面步骤设置的变量,将Retrofit类的所有成员变量都配置完毕。
Retrofit使用建造者模式通过Builder类建立了一个Retrofit实例,具体创建细节是配置了:
- 平台类型对象(Platform - Android)
- 网络请求的url地址(baseUrl)
- 网络请求工厂(callFactory)
默认okhttpcall
- 网络请求适配器工厂的集合(adapterFactories)
- 数据转换器工厂的集合(converterFactories)
- 回调方法执行器(callbackExecutor)
在创建Retrofit对象时,通过更多更灵活的方式去处理需求,如使用不同的Converter、使用不同的CallAdapter,这也就提供了使用RxJava来调用Retrofit的支持
二.创建网络请求接口的实例
还是从最简单的用法开始:
1.根据返回的数据定义接收数据的实体类
2.定义网络请求接口
3.创建接口实例
4.对发送请求的url进行封装生成最终的网络请求对象
2.1 简单使用
2.1.1:
- 1.根据返回的数据定义接收数据的实体类
- 2.定义网络请求接口
//第一步 接收数据的实体类
public class WeatherBean{
......
}
//第二步 定义网络请求接口
public interface APIService {
// 注解GET:采用Get方法发送网络请求
// Retrofit把网络请求的URL分成了2部分:1部分baseurl放在创建Retrofit对象时设置;另一部分在网络请求接口设置(即这里)
// 如果接口里的URL是一个完整的网址,那么放在创建Retrofit对象时设置的部分可以不设置
@GET("simpleWeather/query")
// 接受网络请求数据的方法
// 返回类型为Call<*>,*是解析得到的数据类型,即WeatherBean
//getWeather还包含两个参数 采用@Query注解加入 city(城市),key(聚合数据用户识别码)
Call<WeatherBean> getWeather(@Query("city") String city, @Query("key") String key);
}
补充retrofit对url的拼接规则
- 如果注解中提供的是完整的url,则将作为请求的url
- 如果注解中提供的是不完整的url,且不以“/”开头,则请求的url为baseurl+注解提供的值
- 如果注解中提供的是不完整的url,且以“/”开头,则请求的url为baseurl的主机部分+注解提供的值
retrofit网络请求参数注解用法:
https://www.jianshu.com/p/6f80fe0e85cc
2.1.2
- 3.创建接口实例
- 4.对发送请求的url进行封装生成最终的网络请求对象
//创建接口实例
APIService apiService = retrofit.create(APIService.class);
//对发送请求的url进行封装生成最终的网络请求对象
//这里需要传入两个参数
Call<WeatherBean> call = apiService.getWeather("成都", "***我的key***");
2.2
主要对 3,4进行源码分析
- 3.创建接口实例
- 4.对发送请求的url进行封装生成最终的网络请求对象
//创建接口实例
APIService apiService = retrofit.create(APIService.class);
//对发送请求的url进行封装生成最终的网络请求对象
//这里需要传入两个参数
Call<WeatherBean> call = apiService.getWeather("成都", "***我的key***");
2.2.1
第三步 源码分析APIService apiService = retrofit.create(APIService.class);
我们看retrofit.create(final Class<T> service)
的源码:
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() {// 将代理类的实现交给 InvocationHandler类作为具体的实现
private final Platform platform = Platform.get();
// 在 InvocationHandler类的invoke()实现
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
// 下面三行代码即是 invoke()的实现
//1.读取网络请求接口里的方法,并根据前面配置好的属性配置
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//2.根据配置好的serviceMethod对象创建okHttpCall对象
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
// 3.调用OkHttp,并根据okHttpCall返回rxjava的Observe对象或者返回Call
return serviceMethod.adapt(okHttpCall);
//以上代码中通过动态生成的代理类,调用interfaces接口的方法
//实际上是通过调用InvocationHandler对象的invoke()来完成指定的功能
}
});
}
总结:
return (T) roxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler)
通过代理模式中的动态代理模式,动态生成网络请求接口的代理类,并将代理类的实例创建交给InvocationHandler
类 作为具体的实现,并最终返回一个动态代理对象。
2.2.2 第四步分析 Call<WeatherBean> call = apiService.getWeather("成都", "***我的key***");
-
apiService
对象实际上是动态代理对象Proxy.newProxyInstance()
(第三步中完成),并不是真正的网络请求接口创建的对象 - 当
apiService
调用getWeather时会被动态代理对象Proxy.newProxyInstance()
拦截,然后调用自身的InvocationHandler # invoke()
最终返回一个OkHttpCall的call
对象
三 发送网络请求
Rretrofit默认使用OkHttp,即OkHttpCall类,OkHttpCall提供了两种请求方式:
- 异步请求
OkHttpCall.enqueue()
- 同步请求
OkHttpCall.execute()
3.1 下边是异步请求的分析OkHttpCall.enqueue()
3.1.1 发送请求的步骤
1.对网络请求接口的方法中的每个参数利用对应ParameterHandler进行解析,再根据ServiceMethod对象创建一个OkHttp的Request对象
2.使用OkHttp的Request发送网络请求
3.对返回的数据使用之前设置的数据转换器(GsonConverterFactory)解析返回的数据,最终得到一个Response<T>对象
4.进行线程切换从而在主线程处理返回的数据结果 这里可以使用Rxjava
异步请求会将回调方法交给回调执行器在指定的线程中执行
3.1.2 最简单的使用实现
call.enqueue(new Callback<WeatherBean>() {
@Override
public void onResponse(Call<WeatherBean> call, Response<WeatherBean> response) {
//请求成功后对返回的数据进行处理 更新ui等操作
WeatherBean.ResultBean data = response.body().getResult();
if(data!=null){textView.setText(data.getCity() + ":" + data.getRealtime().getInfo());}
else {textView.setText(response.body().getReason());}
}
@Override
public void onFailure(Call<WeatherBean> call, Throwable t) {
//请求失败显示失败的原因
textView.setText(t.toString());
}
}
3.1.3 源码分析 call.enqueue()
ExecutorCallAdapterFactory.ExecutorCallbackCall.enqueue(final Callback<T> callback)
@Override public void enqueue(final Callback<T> callback) {
//检查callback是否为空
checkNotNull(callback, "callback == null");
// 使用静态代理 delegate进行异步请求
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
//线程切换,从而在主线程 更新ui显示结果
callbackExecutor.execute(new Runnable() {
// 最后Okhttp的异步请求结果返回到callbackExecutor
// callbackExecutor.execute()通过Handler异步回调将结果传回到主线程进行处理(如显示在Activity等等),即进行了线程切换
@Override public void run() {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
我们可以看到在以上源码中 call.enqueue() 通过OkHttpcall的静态代理delegate.enqueue来进行异步请求。
OkHttp异步请求结果返回到callbackExecutor,然后切换线程进行处理
3.1.4 现在来看OkHttpCall..enqueue()源码
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
// 步骤1:创建OkHttp的Request对象,再封装成OkHttp.call
// delegate代理在网络请求前的动作:创建OkHttp的Request对象,再封装成OkHttp.call
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
// 创建OkHttp的Request对象,再封装成OkHttp.call
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
// 步骤2:发送网络请求
// delegate是OkHttpcall的静态代理
// delegate静态代理最终还是调用Okhttp.enqueue进行网络请求
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
// 步骤3:解析返回数据
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
3.1.5 如何进行最后线程切换
线程切换是通过一开始创建Retrofit对象时Platform在检测到运行环境是Android时进行创建的。
static class Android extends Platform {
// 创建默认的回调执行器工厂
// 如果不将RxJava和Retrofit一起使用,一般都是使用该默认的CallAdapter.Factory
// 后面会对RxJava和Retrofit一起使用的情况进行分析
@Override
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
@Override
public Executor defaultCallbackExecutor() {
// 返回一个默认的回调方法执行器
// 该执行器负责在主线程(UI线程)中执行回调方法
return new MainThreadExecutor();
}
// 获取主线程Handler
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
// Retrofit获取了主线程的handler
// 然后在UI线程执行网络请求回调后的数据显示等操作。
handler.post(r);
}
}
// 切换线程的流程:
// 1. 回调ExecutorCallAdapterFactory生成了一个ExecutorCallbackCall对象
// 2. 通过调用ExecutorCallbackCall.enqueue(CallBack)从而调用MainThreadExecutor的execute()通过handler切换到主线程处理返回结果(如显示在Activity等等)
}