https://square.github.io/retrofit/
主要讲:
- retrofit基本使用介绍
- retrofit的常用注解的使用方法
- retrofit主流程讲解
- retrofit关键点面试点讲解
知识点:
- 上传图片:单个 、 多个
- 图文混传
- 下载文件要注意的点
- 涉及到的技术:注解 + 泛型 + 动态代理 (retrofit2 经典,超级多的设计模式)
- retrofit 请求 -> 返回结果,默认 一次性返回到内存,如果是请求文件就可能会导致OOM,这时需要用到 Streaming注解,Streaming 表示响应体的数据用流的方式返回,适用于返回的数据比较大的情况,该注解在下载大文件时特别有用
Retrofit基础资料
https://pan.baidu.com/s/1bMjOFZPQJVvHhj6Oy63DPg
Retrofit是什么
官网介绍是:A type-safe HTTP client for Android and Java,是一个 RESTful 的 HTTP 网络请求框架的封装,但网络请求不是Retrofit来完成的,它只是封装了请求参数、Header、Url、返回结果处理等信息,而请求是由OkHttp3来完成的。
入门
- 导包
//网络请求相关
implementation "com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion"
implementation "com.squareup.retrofit2:retrofit- mock:$rootProject.retrofitVersion"
implementation "com.squareup.retrofit2:converter- gson:$rootProject.retrofitVersion"
implementation 'com.squareup.okhttp3:logging-interceptor:3.5.0'
implementation "com.squareup.retrofit2:converter- scalars:$rootProject.retrofitVersion"
implementation "com.squareup.retrofit2:adapter- rxjava2:$rootProject.retrofitVersion"
implementation "com.squareup.retrofit2:converter- gson:$rootProject.retrofitVersion"
- 定义一个HTTP API接口类
interface WanAndroidApi {
@GET("project/tree/json")
Call<ProjectBean> getProject();
}
- 使用Retrofit类生成WanAndroidApi的接口实现
Retrofit retrofit = new Retrofit.Builder()//建造者模式
.baseUrl("https://www.wanandroid.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
WanAndroidApi wanAndroidApi = retrofit.create(WanAndroidApi.class);// 代理实例
- 发送HTTP请求,返回Response可以同步或者异步处理
Call<ProjectBean> call = wanAndroidApi.getProject();//获取具体的某个业务接口
//同步请求
Response<ProjectBean> response = call.execute();
ProjectBean projectBean = response.body();
//异步请求
call.enqueue(new Callback<ProjectBean>() {
@Override
public void onResponse(final Call<ProjectBean> call, final Response<ProjectBean> response) {
Log.i("Zero","response: " + response.body());
}
@Override
public void onFailure(final Call<ProjectBean> call, final Throwable t){
}
});
注解分类解析
请求方法类
标记类
参数类
原理分析
详见:Retrofit原理流程图及源码分析
关键类功能说明
Retrofit
Retrofit提供的子系统
- serviceMethodCache(自定义的接口映射对象集合)
- baseUrl(请求地址)
- callFactory(默认为OKHttpCall)
- converterFactories(数据解析器工厂集合)
- callAdapterFactories(Call适配器工厂集合)
- callbackExecutor(回调执行,Android平台默认为MainThreadExecutor)
使用Builder模型构建(把对象依赖的零件创建、零件的组装封装起来;以使客户很方便的获取一个复杂对象;)
Platform
Retrofit中用来管理多平台的方法,支持Android、Java8。通过findPlatform获取对应的平台,同时也初始化了defaultCallAdapterFactory工厂。
ServiceMethod
接口映射的网络请求对象,通过动态代理,将自定义接口的标注转换为该对象,将标注及参数生成OkHttp所需的Request对象。Retrofit的create通过动态代理拦截,将每一个自定义接口转换成为一个ServiceMethod对象,并通过通过serviceMethodCache进行缓存。
ServiceMethod描述的是解析之后的请求方法,请求方法的注解、参数、返回类型等解析完了之后都封装在ServiceMethod。
Call
Retrofit定义的网络请求接口,包含execute、enqueue等方法
OkHttpCall
OkHttp的Call实现,通过createRawCall得到真正的 okhttp3.Call对象,用于进行实际的网络请求
CallAdapter.Factory
CallAdapter的静态工厂,包含get的抽象方法,用于生产CallAdapter对象
ExecutorCallAdapterFactory
Android平台默认的CallAdapter工厂,get方法使用匿名内部类实现CallAdapter,返回ExecutorCallbackCall,实现了Call
ExecutorCallbackCall
采用静态代理设计,delegate实际为OkHttpCall,使用callbackExecutor实现回调在主线程中执行
RxJavaCallAdapterFactory
Rxjava平台的CallAdapter工厂,get方法返回RxJavaCallAdapter对象
RxJavaCallAdapter
Rxjava平台的设配器,返回observable对象
Converter.Factory
数据解析器工厂,用于生产Converter实例
GsonConverterFactory
数据解析工厂实例,返回了GsonResponseBodyConverter数据解析器
GsonResponseBodyConverter
Gson的数据解析器,将服务端返回的json对象转换成对应的java模型
Response
Retrofit网络请求响应的Response
关键的几个流程
- Retrofit 如何将定义的interface转换成网络请求?
- Retrofit的Converter机制是如何实现?
- Retrofit的CallAdapter机制是如何实现?
Converter种类
CallAdapter种类
如何自定义一个Converter及CallAdapter?
Retrofit中的设计模式
1. 建造者模式
Retrofit对象的创建、ServiceMethod对象创建都使用Build模式,将复杂对象的创建和表示分离,调用者不需要知道复杂的创建过程,使用Build的相关方法进行配置创建对象。
2. 外观模式
Retrofit对外提供了统一的调度,屏蔽了内部的实现,使得使用该网络库简单便捷。
门面模式: 提供一个统一的接口去访问多个子系统的多个不同的接口,它为子系统中的一组接口提供一个统一的高层接口,使子系统更容易使用。
3. 动态代理模式
通过动态代理的方式,当调用Retrofit的create()方法时,会进行动态代理监听。当执行具体的接口方法时,会回调InvocationHandler。通过反射解析method的标注及参数,生成ServiceMethod对象。
4. 静态代理模式
Android平台默认的适配器ExecutorCallbackCall,采用静态代理的模式。具体的实现delegate为OkHttpCall。
5. 工厂模式
Converter及CallAdapter的创建都采用了工厂模式进行创建。
6. 适配器模式
CallAdapter的adapt采用了适配器模式,使得interface的返回对象可以动态扩展,增强了灵活性。
OkHttp, Retrofit, Volley应该如何选择?
Retrofit原理流程图及源码分析
Retrofit原理整体可以分为三大部分:
第一部分:创建retrofit对象,通过retrofit对象获得接口的动态代理对象
第二部分:调用动态代理对象的接口方法时获得retrofit的Call对象
第三部分:调用Call.execute或者Call.enqueue执行网络请求,将请求结果转换为Response对象
1.获得接口的动态代理对象
通过动态代理来实现。
先生成retrofit对象:
//Retrofit.java
public Retrofit build() {
...
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();//创建OkHttpClient对象执行http请求,OkHttpClient就是okhttp3.Call.Factory
}
//callbackExecutor 用于将响应结果发送到UI主线程
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> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
}
DefaultCallAdapterFactory创建的是ExecutorCallbackCall对象,ExecutorCallbackCall封装了Call请求和回调处理对象。
传递给retrofit对象的是接口,如何获得接口的实例对象?
看下retrofit.create()方法:
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override public @Nullable Object invoke(Object proxy, Method method,
@Nullable 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);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
通过动态代理实现传递的是接口,而返回的是实现了该接口的代理对象。传递的参数是service,返回的是实现了service接口的代理实例对象。
2.调用动态代理对象的接口方法时获得retrofit的Call对象
当调用代理实例对象实现的接口方法(比如例子中的wanAndroidApi.getProject()
方法)时最终都会调用invoke方法:
@Override public @Nullable Object invoke(Object proxy, Method method,
@Nullable 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);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
看下loadServiceMethod方法:
//Retrofit.java
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//解析方法上的注解等信息
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
这里做了缓存,因为ServiceMethod.parseAnnotations解析注解时会用到大量的反射调用,非常耗性能,使用缓存来缓存解析的结果,解析过了就不需要再次解析了,直接从缓存中获取。
用到反射时就要考虑使用缓存进行缓存结果,提高性能。Android源码中很多地方都这么用,比如:LayoutInflater的createViewFromTag()方法根据xml解析view时也做了缓存。
ServiceMethod.parseAnnotations方法是真正解析方法上的注解:
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}
调用RequestFactory.parseAnnotations方法解析请求的参数,封装在RequestFactory中:
//RequestFactory.java
final class RequestFactory {
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
private final Method method;//请求的方法
private final HttpUrl baseUrl;//请求的url
final String httpMethod;//时get请求还是post请求
private final @Nullable String relativeUrl;//相对url
private final @Nullable Headers headers;//请求头
private final @Nullable MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers;//请求参数
final boolean isKotlinSuspendFunction;
...
RequestFactory 也是建造者模式:
//RequestFactory.java
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();//获取方法上的所有注解
this.parameterTypes = method.getGenericParameterTypes();//获取方法上的泛型类型
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
获取到注解后进行解析:
//RequestFactory.java
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
parseMethodAnnotation方法解析各个注解:
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);
} else if (annotation instanceof HEAD) {
parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
} else if (annotation instanceof PATCH) {
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
} else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError(method, "@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
这样就将接口的方法上的注解封装成http请求的参数。
回到ServiceMethod.parseAnnotations方法,解析完请求参数后对返回类型进行判断:
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
RequestFactory.parseAnnotations进行解析完请求参数后再次调用HttpServiceMethod.parseAnnotations进行第二次解析(HttpServiceMethod是ServiceMethod的子类):
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
...
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
...
}
为什么要调用HttpServiceMethod.parseAnnotations进行第二次解析?
CallAdapter就是根据方法的返回值类型进行创建的。
如果返回值类型是默认的Call,比如:
interface WanAndroidApi {
fun getProject(): Call<ProjectBean>
...
}
那么返回的就是DefaultCallAdapterFactory#ExecutorCallbackCall这种类型的Call。
如果返回类型是RxJava的Observable类型,比如:
public interface WangAndroidApi {
// 总数据
@GET("project/tree/json")
Observable<ProjectBean> getProject();
...
}
那么返回的就是RxJava2CallAdapterFactory创建的RxJava2CallAdapter创建的Observable:
//RxJava2CallAdapter.java
@Override
public Object adapt(Call<R> call) {
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
Observable<?> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
...
}
如何实现的?看下createCallAdapter方法:
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
try {
//noinspection unchecked
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create call adapter for %s", returnType);
}
}
最终会调用nextCallAdapter方法获取对应的CallAdapter.Factory
//Retrofit.java
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
Objects.requireNonNull(returnType, "returnType == null");
Objects.requireNonNull(annotations, "annotations == null");
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
遍历callAdapterFactories根据returnType和annotations找到CallAdapter.Factory,然后根据CallAdapter.Factory获取CallAdapter,而这些callAdapterFactories是在Retrofit创建的时候初始化的,默认添加的就是DefaultCallAdapterFactory:
//Retrofit.java
public Retrofit build() {
...
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
}
各种类型的 CallAdapterFactory就是为了创建 CallAdapter而存在的。
loadServiceMethod方法解析完之后就调用invoke方法:
@Override public @Nullable Object invoke(Object proxy, Method method,
@Nullable 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);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
//DefaultCallAdapterFactory.java
@Override public Call<Object> adapt(Call<Object> call) {
return executor == null
? call
: new ExecutorCallbackCall<>(executor, call);
}
生成一个ExecutorCallbackCall对象,即最终得到了Call对象,这里用到的是适配器模式。
总结:
1.调用ServiceMethod.parseAnnotations进行解析请求方法的参数,封装在RequestFactory中。
2.调用HttpServiceMethod.parseAnnotations进行解析请求方法的返回类型,得到retrofit的Call对象。
3.调用Call.execute或者Call.enqueue执行网络请求,将请求结果转换为Response对象
得到retrofit的Call对象后就是执行网络请求,将请求结果转换为Response对象,然后返回。下面进行分析。
默认的Call对象是DefaultCallAdapterFactory#ExecutorCallbackCall,看下源码:
//DefaultCallAdapterFactory.java
...
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
...
}
有两个成员变量,delegate和callbackExecutor
这里用的高了静态代理模式,这个delegate就是创建的OkHttpCall对象:
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
也就是说最终是通过OkHttpCall执行网络请求的。
callbackExecutor就是http请求结果的处理器。
所以当调用ExecutorCallbackCall的enqueue方法时,最终调用的是OkHttpCall的enqueue方法执行真正的网络请求:
@Override public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
okhttp3.Call call;//okhttp3的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();
} catch (Throwable t) {
throwIfFatal(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) {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
@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) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
});
}
调用okhttp3的Call对象执行真正的网络请求。获取到okhttp3返回的结果rawResponse后,调用parseResponse方法将结果转化为retrofit的Response,转换时使用的是
//OkHttpCall.java
try {
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
}
responseConverter是从retrofit初始化时的converterFactories中获取的,比如我们初始化retrofit的时候添加了GsonConverterFactory:
val retrofit = Retrofit.Builder()
//Retrofit2的baseUrl必须以 /(斜杆)结束,否则会抛出一个IllegalArgumentException
.baseUrl("https://www.wanandroid.com/")
.addConverterFactory(GsonConverterFactory.create())//添加json解析器,因为要用到json解析
.build()
那么解析响应的时候就用到GsonConverterFactory。然后把结果封装在retrofit的Response中,返回给最初调用的地方:
getProjectCall.enqueue(object : Callback<ProjectBean> {
override fun onFailure(call: Call<ProjectBean>, t: Throwable) {
Log.i(TAG, "错误:${t.message}")
}
override fun onResponse(call: Call<ProjectBean>, response: Response<ProjectBean>) {
Log.i(TAG, "成功: ${response.body()}")
}
})
总结:
- retrofit底层使用okhttp执行网络请求的优点:okhttp的请求速度快,连接池复用机制,okio效率高
- 由以上源码分析可知,okhttp的Call对象并不是在创建Retrofit对象时创建的,而是在执行retrofit的Call对象的execute或者enqueue方法时创建的。
- okhttp与HttpUrlConnection和HttpClient一样,都是执行http请求的,但是okhttp性能好,速度快,效率高。
常见面试题
Retrofit的Call和Okhttp的Call的区别
//retrofit2.Call.java
public interface Call<T> extends Cloneable {
...
}
Retrofit的Call是对请求方法的封装。
//okhttp3.Call.java
public interface Call extends Cloneable {
...
}
Okhttp的Call是用于真正的执行网络请求。
Retrofit的Call调用exexute或则enqueue时会创建Okhttp的Call对象执行网络请求。
Retrofit用到哪些设计模式
重点要阐述动态代理模式和反射。