简介
Retrofit是一个Restful设计风格的Http网络请求框架,基于OkHttp
功能
- 基于OkHttp、遵循restful api设计风格
- 通过注解配置网络请求参数
- 支持同步、异步的网络请求
- 支持多种数据的解析和序列化格式(Gson、Json、XML、Protobuf)
- 提供了对RxJava的支持
优点
功能强大、简洁易用、可扩展性好
应用场景
任何网络请求的场景都应该优先选择,特别是后台API遵循restful API设计风格或项目中使用到RxJava时
小结
-
准确来说,Retrofit是一个RESTful的Http网络请求框架的封装
-
原因:网络请求的工作本质上是Okhttp完成,而Retrofit仅负责啊网络请求接口的封装
-
App应用程序通过Retrofit请求网络,实际上是使用Retrofit接口层封装请求参数、Header、Url等信息,之后由OkHttp完成后续的请求操作
-
在服务端返回数据之后,Okhttp将原始的结果交给Retrofit,Retrofit根据用户的需求对结果进行解析
使用
- 引入Retrofit库的依赖
- 创建接收服务器返回数据的类
- 创建用于描述网络请求的接口 :Retrofit将http请求抽象成java接口。用动态代理动态将该接口的注解翻译成一个Http请求,最后再执行Http请求
- 创建Retrofit实例
- 创建网络请求接口实例并配置网络请求参数
- 发送网络请求(异步/同步)
封装了数据转换、线程切换的操作
- 处理服务器返回的数据
注解类型
注解说明
Retrofit把网络请求的Url分成了两部分设置:
// 第1部分:在网络请求接口的注解设置
@GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car")
Call<Translation> getCall();
// 第2部分:在创建Retrofit实例时通过.baseUrl()设置
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/") //设置网络请求的Url地址
.addConverterFactory(GsonConverterFactory.create()) //设置数据解析器
.build();
// 从上面看出:一个请求的URL可以通过 替换块 和 请求方法的参数 来进行动态的URL更新。
// 替换块是由 被{}包裹起来的字符串构成
// 即:Retrofit支持动态改变网络请求根目录
网络请求的完整Url : 在创建Retrofit实例时通过.baseUrl()设置 + 网络请求接口的注解设置
标记
@FormUrlEncoded
- 作用:表示发送form-encoded的数据
每个键值对需要用@Filed来注解键名,随后的对象需要提供值
@Multipart
- 作用:表示发送form-encoded数据(适用于有文件上传的场景)
每个键值对需要用@Part来注解键名,随后的对象需要提供值
具体使用如下:
public interface GetRequest_Interface {
/**
*表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
* <code>Field("username")</code> 表示将后面的 <code>String name</code> 中name的取值作为 username 的值
*/
@POST("/form")
@FormUrlEncoded
Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);
/**
* {@link Part} 后面支持三种类型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意类型
* 除 {@link okhttp3.MultipartBody.Part} 以外,其它类型都必须带上表单字段({@link okhttp3.MultipartBody.Part} 中已经包含了表单字段的信息),
*/
@POST("/form")
@Multipart
Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file);
}
// 具体使用
GetRequest_Interface service = retrofit.create(GetRequest_Interface.class);
// @FormUrlEncoded
Call<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24);
// @Multipart
RequestBody name = RequestBody.create(textType, "Carson");
RequestBody age = RequestBody.create(textType, "24");
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file);
Call<ResponseBody> call3 = service.testFileUpload1(name, age, filePart);
网络请求参数
详细说明
a. @Header、@Headers
- 作用:添加请求头/添加不固定的请求头
- 具体使用如下:
// @Header
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
// @Headers
@Headers("Authorization: authorization")
@GET("user")
Call<User> getUser()
// 以上的效果是一致的。
// 区别在于使用场景和使用方式
// 1. 使用场景:@Header用于添加不固定的请求头,@Headers用于添加固定的请求头
// 2. 使用方式:@Header作用于方法的参数;@Headers作用于方法
b. @Body
- 作用:以Post方式传递自定义数据类型给服务器
- 特别注意:如果提交的是一个Map,那么作用相当于@Field
Map经过FormBody.Builder类处理成符合OkHttp格式的表单,如:
FormBody.Builder builder = new FormBody.Builder();
builder.add("key","value");
c. @Filed、@FiledMap
- 作用:发送Post请求时提交请求的表单字段
- 具体使用:与@FormUrlEncoded注解配合使用
public interface GetRequest_Interface {
/**
*表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
* <code>Field("username")</code> 表示将后面的 <code>String name</code> 中name的取值作为 username 的值
*/
@POST("/form")
@FormUrlEncoded
Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);
/**
* Map的key作为表单的键
*/
@POST("/form")
@FormUrlEncoded
Call<ResponseBody> testFormUrlEncoded2(@FieldMap Map<String, Object> map);
}
// 具体使用
// @Field
Call<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24);
// @FieldMap
// 实现的效果与上面相同,但要传入Map
Map<String, Object> map = new HashMap<>();
map.put("username", "Carson");
map.put("age", 24);
Call<ResponseBody> call2 = service.testFormUrlEncoded2(map);
d. @Query、@QueryMap
- 作用
用于@GET方法的查询参数(Query = Url中’?'后面的key-value)
如:url = http://www.println.net/?cate=android 其中,Query = cate
@GET("/")
Call<String> cate(@Query("cate") String cate);
}
// 其使用方式同 @Field与@FieldMap,这里不作过多描述
f. @Path
-
作用
URL地址的缺省值 -
具体使用
public interface GetRequest_Interface {
@GET("users/{user}/repos")
Call<ResponseBody> getBlog(@Path("user") String user );
// 访问的API是:https://api.github.com/users/{user}/repos
// 在发起请求时, {user} 会被替换为方法的第一个参数 user(被@Path注解作用)
}
g. @Url
-
作用
直接传入一个请求的Url变量用于URL设置 -
具体使用
public interface GetRequest_Interface {
@GET
Call<ResponseBody> testUrlAndQuery(@Url String url, @Query("showAll") boolean showAll);
// 当有URL注解时,@GET传入的URL就可以省略
// 当GET、POST...HTTP等方法中没有设置Url时,则必须使用 {@link Url}提供
}
原理
网络请求的过程
Retrofit与普通网络请求的比较
具体过程如下:
1.通过解析 网络请求接口的注解 配置网络请求参数
2.通过 动态代理 生成网络请求对象
3.通过 网络请求适配器 将网络请求对象进行平台适配
4.通过 网络请求执行器 发送网络请求
5.通过 数据转换器 解析服务器返回的数据
6.通过回调执行器切换线程(子线程 -> 主线程)
7.用户在主线程处理返回结果
Retrofit类
<-- Retrofit类 -->
public final class Retrofit {
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
// 网络请求配置对象(对网络请求接口中方法注解进行解析后得到的对象)
// 作用:存储网络请求相关的配置,如网络请求的方法、数据转换器、网络请求适配器、网络请求工厂、基地址等
private final HttpUrl baseUrl;
// 网络请求的url地址
private final okhttp3.Call.Factory callFactory;
// 网络请求器的工厂
// 作用:生产网络请求器(Call)
// Retrofit是默认使用okhttp
private final List<CallAdapter.Factory> adapterFactories;
// 网络请求适配器工厂的集合
// 作用:放置网络请求适配器工厂
// 网络请求适配器工厂作用:生产网络请求适配器(CallAdapter)
// 下面会详细说明
private final List<Converter.Factory> converterFactories;
// 数据转换器工厂的集合
// 作用:放置数据转换器工厂
// 数据转换器工厂作用:生产数据转换器(converter)
private final Executor callbackExecutor;
// 回调方法执行器
private final boolean validateEagerly;
// 标志位
// 作用:是否提前对业务接口中的注解进行验证转换的标志位
<-- Retrofit类的构造函数 -->
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = unmodifiableList(converterFactories);
this.adapterFactories = unmodifiableList(adapterFactories);
// unmodifiableList(list)近似于UnmodifiableList<E>(list)
// 作用:创建的新对象能够对list数据进行访问,但不可通过该对象对list集合中的元素进行修改
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
...
// 仅贴出关键代码
}
成功建立一个Retrofit对象的标准:配置好Retrofit类里的成员变量
- serviceMethod : 包含所有网络请求信息的对象
- baseUrl : 网络请求的url地址
- callFactory : 网络请求工厂
- adapterFactories : 网络请求适配器工厂的集合
- converterFactories : 数据转换工厂的集合
- callbackExecutor : 回调方法执行器
CallAdapter
- 定义 : 网络请求执行器(Call)的适配器
1.Call在Retrofit里默认是OkHttpCall
2.在Retrofit中提供了四种CallAdapterFactory:ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory
- 作用:将默认的网络请求执行器(OkHttpCall)转换成适合被不同平台来调用的网络请求执行器形式
1.例如:一开始Retrofit只打算利用OkHttpCall通过ExecutorCallbackCall切换线程,但是后来发现使用RxJava更加方便(不需要Handler切换线程)。想要实现Rxjava的方式,就要使用RxJavaCallAdapterFactoryCallAdapter将OkHttpCall转换成RxJava(Scheduler);
2.Retrofit还支持java8、Guava平台
- 好处 : 用最小的代价兼容更多平台,即能适配更多的使用场景
Builder类
<-- Builder类-->
public static final class Builder {
private Platform platform;
private okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private List<Converter.Factory> converterFactories = new ArrayList<>();
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private Executor callbackExecutor;
private boolean validateEagerly;
// 从上面可以发现, Builder类的成员变量与Retrofit类的成员变量是对应的
// 所以Retrofit类的成员变量基本上是通过Builder类进行配置
// 开始看步骤1
<-- 步骤1 -->
// Builder的构造方法(无参)
public Builder() {
this(Platform.get());
// 用this调用自己的有参构造方法public Builder(Platform platform) ->>步骤5(看完步骤2、3、4再看)
// 并通过调用Platform.get()传入了Platform对象
// 继续看Platform.get()方法 ->>步骤2
// 记得最后继续看步骤5的Builder有参构造方法
}
...
}
<-- 步骤2 -->
class Platform {
private static final Platform PLATFORM = findPlatform();
// 将findPlatform()赋给静态变量
static Platform get() {
return PLATFORM;
// 返回静态变量PLATFORM,即findPlatform() ->>步骤3
}
<-- 步骤3 -->
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
// Class.forName(xxx.xx.xx)的作用:要求JVM查找并加载指定的类(即JVM会执行该类的静态代码段)
if (Build.VERSION.SDK_INT != 0) {
return new Android();
// 此处表示:如果是Android平台,就创建并返回一个Android对象 ->>步骤4
}
} catch (ClassNotFoundException ignored) {
}
try {
// 支持Java平台
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
try {
// 支持iOS平台
Class.forName("org.robovm.apple.foundation.NSObject");
return new IOS();
} catch (ClassNotFoundException ignored) {
}
// 从上面看出:Retrofit2.0支持3个平台:Android平台、Java平台、IOS平台
// 最后返回一个Platform对象(指定了Android平台)给Builder的有参构造方法public Builder(Platform platform) --> 步骤5
// 说明Builder指定了运行平台为Android
return new Platform();
}
...
}
<-- 步骤4 -->
// 用于接收服务器返回数据后进行线程切换在主线程显示结果
static class Android extends Platform {
@Override
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
// 创建默认的网络请求适配器工厂
// 该默认工厂生产的 adapter 会使得Call在异步调用时在指定的 Executor 上执行回调
// 在Retrofit中提供了四种CallAdapterFactory: ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory
// 采用了策略模式
}
@Override
public Executor defaultCallbackExecutor() {
// 返回一个默认的回调方法执行器
// 该执行器作用:切换线程(子->>主线程),并在主线程(UI线程)中执行回调方法
return new MainThreadExecutor();
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
// 获取与Android 主线程绑定的Handler
@Override
public void execute(Runnable r) {
handler.post(r);
// 该Handler是上面获取的与Android 主线程绑定的Handler
// 在UI线程进行对网络请求返回数据处理等操作。
}
}
// 切换线程的流程:
// 1. 回调ExecutorCallAdapterFactory生成了一个ExecutorCallbackCall对象
//2. 通过调用ExecutorCallbackCall.enqueue(CallBack)从而调用MainThreadExecutor的execute()通过handler切换到主线程
}
// 下面继续看步骤5的Builder有参构造方法
<-- 步骤5 -->
// Builder类的构造函数2(有参)
public Builder(Platform platform) {
// 接收Platform对象(Android平台)
this.platform = platform;
// 通过传入BuiltInConverters()对象配置数据转换器工厂(converterFactories)
// converterFactories是一个存放数据转换器Converter.Factory的数组
// 配置converterFactories即配置里面的数据转换器
converterFactories.add(new BuiltInConverters());
// BuiltInConverters是一个内置的数据转换器工厂(继承Converter.Factory类)
// new BuiltInConverters()是为了初始化数据转换器
}
Builder类设置了默认的属性
- 平台类型对象 : Android
- 网络请求适配器工厂 : CallAdapterFactory
CallAdapter用于对原始Call进行再次封装,如Call到Observable
- 数据转换器工厂 : converterFactory
- 回调执行器 : callbackExecutor
baseUrl
<-- 步骤1 -->
public Builder baseUrl(String baseUrl) {
// 把String类型的url参数转化为适合OKhttp的HttpUrl类型
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
// 最终返回带httpUrl类型参数的baseUrl()
// 下面继续看baseUrl(httpUrl) ->> 步骤2
return baseUrl(httpUrl);
}
<-- 步骤2 -->
public Builder baseUrl(HttpUrl baseUrl) {
//把URL参数分割成几个路径碎片
List<String> pathSegments = baseUrl.pathSegments();
// 检测最后一个碎片来检查URL参数是不是以"/"结尾
// 不是就抛出异常
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
baseUrl()用于配置Retrofit类的网络请求url地址。它可以将传入的String类型的url转换为Okhttp的HttpUrl类型的url
GsonConverterFactory.create()
public final class GsonConverterFactory extends Converter.Factory {
<-- 步骤1 -->
public static GsonConverterFactory create() {
// 创建一个Gson对象
return create(new Gson()); ->>步骤2
}
<-- 步骤2 -->
public static GsonConverterFactory create(Gson gson) {
// 创建了一个含有Gson对象实例的GsonConverterFactory
return new GsonConverterFactory(gson); ->>步骤3
}
private final Gson gson;
<-- 步骤3 -->
private GsonConverterFactory(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
this.gson = gson;
}
所以,GsonConverterFactory.create()是创建了一个含有Gson对象实例的GsonConverterFactory,并返回给addConverterFactory
addConverterFactory()
// 将上面创建的GsonConverterFactory放入到 converterFactories数组
// 在第二步放入一个内置的数据转换器工厂BuiltInConverters()后又放入了一个GsonConverterFactory
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
1.Retrofit默认使用Gson进行解析
2.若使用其他解析方式(Json、XML、Protobuf),也可以通过自定义数据解析器来实现(必须继承Converter.Factory)
异步请求OkHttpCall.enqueue()
发送请求的过程
-
对网络请求接口的方法中的每个参数利用对应ParameterHandler进行解析,再根据ServiceMethod对象创建一个OkHttp的Request对象
-
使用OkHttp的Request发送网络请求
-
对返回的数据使用之前设置的数据转换器(GsonConverterFactory)解析返回的数据,最终得到一个Response对象
-
进行线程切换从而在主线程处理返回的数据结果
若使用了RxJava,则直接回调到主线程
异步请求的过程跟同步请求类似,唯一不同的是:异步请求会将回调方法交给回调执行器在指定的线程中执行(UI线程)
总结
Retrofit使用建造者模式通过Builder类建立了一个Retrofit实例,具体创建细节:
-
平台类型对象(plateform-Android)
-
网络请求的url地址(baseUrl)
-
网络请求工厂(callFactory)
默认使用OkHttpCall
- 网络请求适配器工厂的集合(adapterFactories)
本质是配置了网络请求适配器工厂——默认是ExecutorCallAdapterFactory
- 数据转换器工厂的集合(converterFactories)
本质是配置了数据转换器工厂
- 回调方法执行器(callbackExecutor)
默认回调方法执行器作用是:切换线程(子线程 -> 主线程)