1.Retrofit
Retrofit是基于OkHttp封装的网络请求框架,网络请求的工作本质上是OkHttp完成的,而Retrofit仅负责网络请求接口的封装。
OkHttp的缺点:
①配置网络请求非常繁琐,尤其是配置复杂网络请求body、请求头、参数的时候。
②获取结果后需要用户手动解析ResponseBody,难以复用。
③无法自动进行线程切换。
④如果存在嵌套网络请求,就会陷入“回调地狱”。
Retrofit封装OkHttp主要优化了以下几点:
①build模式创建网络请求基本配置。
②用注解类组合HTTP网络请求。
③提供Gson解析返回的json数据。
④Executor完成线程切换。
Retrofit请求实现的核心在于注解、动态代理和反射。通过对接口层的封装,将请求参数、header、url这些网络请求信息封装,然后交给OkHttp完成实际的请求操作。在服务端返回数据后,OkHttp将原始的结果交给Retrofit,然后Retrofit根据不同的场景进行不同的数据解析方式。
使用Retrofit,开发者不用关注网络通信的细节,只需要在接口文件中声明一系列方法和返回值,然后通过注解的方式指定该方法对应哪个服务器接口,以及需要提供哪些参数。当在程序中调用该方法时,Retrofit会自动向对应的服务器接口发起请求,并将响应的数据解析成返回值声明的类型。这样可以用更加面向对象的思维来进行网络操作。
2.Retrofit用法
①添加依赖
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation("com.squareup.okhttp3:okhttp:4.9.1")
Retrofit是基于OkHttp二次封装的网络请求库, 所以要导入OkHttp的依赖。
gson是用来解析Json数据使用的。Retrofit也支持其他解析工具比如fastJson。
②build创建Retrofit实例
Retrofit mRetrofit = new Retrofit.Builder()
.baseUrl(Config.baseUrl)
.addConverterFactory( GsonConverterFactory.create())) //数据解析器
.callbackExecutor( Executors.newSingleThreadExecutor())//线程池
.build();
baseUrl:网络地址不能为空,且强制要求必须以斜杠/结尾。
callbackExecutor:使用单独的线程处理 (这很重要,一般网络请求如果不设置可能不会报错,但是如果是下载文件就会报错)。
③创建数据返回后的Bean类
public class MyLoginBean {
private int code;
private String msg;
public int getCode() { return code; }
public void setCode(int code) {
this.code = code;
}
public String getMsg() { return msg; }
public void setMsg(String msg) {
this.msg = msg;
}
}
④创建网络请求接口
public interface MyHttpList {
@FormUrlEncoded
@POST("test/login_test")
Call<MyLoginBean> login(@Field("username") String username, @Field("password") String password);
}
这是一个接口类,MyLoginBean是数据返回后的Bean类,Retrofit会自动使用导入的Gson解析。@Field("username") 为post值的key。每个参数只能有一个注解。
注意:@POST("test/login_test")路径最前面不能加斜杠/,否则它会自动裁剪路径,这样会导致路径错误。
Retrofit把网络请求的url分成两部分:第一部分是在创建Retrofit对象的时候,通过baseUrl设置的;另一部分就是在这个接口当中通过注解的形式传入的。注意,如果在接口中注解后面设置的url是一个完整的路径或完整的网址,那在创建Retrofit对象的时候就不需要设置baseUrl了。
⑥发起同步网络请求
MyHttpList httpList = mRetrofit.create( MyHttpList.class);
final Call<MyLoginBean> call = httpList.login("admin", "123456");
new Thread(new Runnable() {
@Override
public void run() {
Response<MyLoginBean> response = call.execute(); //同步请求网络
MyLoginBean bean = response.body();
Log.e(TAG, "onResponse: code=" + bean.getCode() + " message=" + bean.getMessage());
}
}).start();
首先用Retrofit.create()创建请求接口的代理,拿到call对象之后调用execute同步方法,返回一个response对象,然后通过response获取从后端请求返回的数据,因为gson解析器做好了解析,这里只需要response.body().getCode()、response.body().getMsg());就能获取服务端返回的json数据里面key对应value值。
create()方法内部使用到了观察者模式、代理模式以及外观模式。
注意:因为是同步方法,不能直接在ui线程里面操作,不然会造成线程阻塞直接报出anr,所以在使用call同步方法时,要开启一个子线程操作。
⑦发起异步网络请求
MyHttpList httpList = mRetrofit.create( MyHttpList.class);
Call<MyLoginBean> call = httpList.login( "admin", "123456");
call.enqueue(new Callback<MyLoginBean>() {
@Override
public void onResponse(Call<MyLoginBean> call, Response<MyLoginBean> response) {
MyLoginBean bean = response.body();
Log.e(TAG, "onResponse: code=" + bean.getCode() + " message=" + bean.getMessage());
}
@Override
public void onFailure(Call<MyLoginBean> call, Throwable t) {
Log.e(TAG, "onFailure: 网络请求失败="+t.getMessage());
}
});
调用call对象的enqueue异步方法,需要实现Callback接口里面的回调方法。因为是异步操作,所以不需要再开启线程来处理,框架已经处理好了。
⑧添加配置的OkHttpClient(主要使用请求超时/拦截器等功能)
如果Retrofit中需要设置请求超时时间、拦截器等时,可以使用OkHttp的方式来配置。
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.retryOnConnectionFailure(false)
.connectTimeout( 20,TimeUnit.SECONDS)
.readTimeout(20,TimeUnit.SECONDS)
.writeTimeout(20,TimeUnit.SECONDS)
.addInterceptor() //设置拦截器
.authenticator() //设置认证器
.proxy()//设置代理
.build();
mRetrofit = new Retrofit.Builder()
.client(okHttpClient)
……
.build();
3.源码分析
①构建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URL)
.callFactory(…)
.addConverterFactory(GsonConverterFacto ry.create())
.build();
Retrofit使用build()方法构建,通过设置各种工厂,为后面做好准备。
Retrofit.java:
public Retrofit build() {
//1.设置callFactory属性为.callFactory()传入的参数。如果没有指定callFactory则默认为OkHttpClient。如果需要对OkHttpClient进行详细的设置,就需要自己构建并传入OkHttpClient对象
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//2.设置callbackExecutor属性为.callbackExecutor()传入的参数。如果没有指定就获取platform(Android平台)的defaultCallbackExecutor,最终获取到的是一个MainThreadExecutor,它里面有一个主线程的Handler,调用MainThreadExecutor的execute就可以使用Handler向主线程post一个任务
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//3.设置callAdapterFactories属性,其中CallAdapter.Factory主要用于对retrofit.Call对象进行转化,其中的优先级顺序为:①外界传入的callAdapterFactories②platform.defaultCallAdapterFactories()
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll( platform.defaultCallAdapterFactories(callbackExecutor));
//4.设置converterFactories属性,其中Converter.Factory主要用于转化数据,例如将返回的ResponseBody转化为对象等。其中的优先级顺序:①BuiltInConverters②外界传入的converterFactories③platform.defaultConverterFactories()
List<Converter.Factory> converterFactories = new ArrayList<>(1+this.converterFactories.size() + platform.defaultConverterFactoriesSize());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll( this.converterFactories);
converterFactories.addAll( platform.defaultConverterFactories());
//5.通过设置的这些参数构建Retrofit对象并返回
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories), unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
build方法主要给几个重要参数赋值,分别是:callFactory、callbackExecutor、callAdapterFactories、converterFactories。
callFactory是网络请求器的工厂,用于生产Call请求对象,不管是同步请求还是异步请求都是通过这个Call来调用的。从这里也可以看出,在Retrofit内部默认使用的是okhttp的请求方式。
adapterFactories是网络请求适配器工厂的集合,用于放置网络请求适配器工厂。网络请求适配器工厂是用于生产CallAdapter网络请求适配器的。
converFactories是数据转换器工厂的集合,用于放置数据转换器工厂。数据转换器工厂是用于生产数据转换器的,比如可以放入Gson作为转换器,服务器返回数据为Json类型,然后通过Gson解析器进行解析,并在主线程中去显示。
callbackExecutor是回调方法的执行器,主线程切换到子线程,子线程切换到主线程,都是通过这个Executor来执行的。
②retrofit.create()生成代理对象
使用Retrofit进行网络请求的时候,需要先定义一个接口类,然后调用retrofit.create(serviceClass)生成接口的实例。retrofit.create()把网络请求配置的接口转换成一个实现了该接口的对象,使用的核心技术就是JDK动态代理。
Retrofit.java:
public <T> T create(final Class<T> service) {
// 动态代理,返回代理对象
return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() {
private final Object[] emptyArgs = new Object[0]; // 定义空的参数数组
//每次调用接口中的方法都会走该方法,相当于就是接口方法的实现。参数proxy:代理对象,method:当前调用的接口方法,args:方法的参数
@Override public Object invoke(Object proxy, Method method, Object[] args) {
if (method.getDeclaringClass() == Object.class) { // 如果是Object类中的方法则不做额外处理
return method.invoke(this, args);
}
// 重点,获取一个ServiceMethod对象,然后调用它的invoke方法,网络请求的具体实现、处理就在这里
return loadServiceMethod(method) .invoke(args != null ? args : emptyArgs);
}
});
}
retrofit.create()方法创建并返回了一个代理对象。在InvocationHandler的invoke方法里调用了loadServiceMethod方法获取一个ServiceMethod对象,一个ServiceMethod对象就代表网络请求接口里的一个方法,获取到ServiceMethod后,调用它的invoke方法进行网络请求。
重点对loadServiceMethod(method).invoke(args != null ? args : emptyArgs);进行分析,这个过程会组织网络请求、解析响应结果、将响应结果返回。
这里分为loadServiceMethod()和invoke()两步。
1)第一步 loadServiceMethod返回CallAdapted
loadServiceMethod()方法的主要任务就是解析网络请求接口方法上的注解信息,得到数据适配器、数据解析器对象,然后封装成一个CallAdapted返回。
Retrofit.java:
ServiceMethod<?> loadServiceMethod(Method method) {
//先从缓存中找,判断是否有method对应的ServiceMethod对象,有则直接返回
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
// 缓存中没找到
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
// 创建ServiceMethod对象并把它加入缓存中
result = ServiceMethod.parseAnnotations( this, method);
serviceMethodCache.put(method, result);
}
}
return result; //返回ServiceMethod对象
}
先从serviceMethodCache中查看method是否有对应的ServiceMethod,有则直接返回,没有则调用ServiceMethod.parseAnnotations方法对method的注解进行处理,并将得到的ServiceMethod对象加入到ServiceMethodCache里面。这里将Method作为ConcurrentHashMap的Key,从而实现了对ServiceMethod的缓存与复用。
(1)ServiceMethod.parseAnnotations()方法
ServiceMethod.java:
static <T> ServiceMethod<T> parseAnnotations( Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
return HttpServiceMethod.parseAnnotations( retrofit, method, requestFactory);
}
ServiceMethod的parseAnnotations方法用于构建一个ServiceMethod,主要分为两步:
1)调用RequestFactory.parseAnnotations方法创建RequestFactory,这里主要是获取网络请求接口中对应方法的注解信息以及方法参数的注解信息,然后解析注解,准备网络请求的必要信息。
2)调用HttpServiceMethod.parseAnnotations方法(传入前面获取的requestFactory),继续进行注解的解析,最终获取并返回一个HttpServiceMethod对象。
(2)RequestFactory.parseAnnotations()方法
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
这是一个建造者模式。它将method传入RequestFactory.Builder,再调用build方法创建了一个RequestFactory对象。
查看RequestFactory.Builder的构造方法:
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations(); // 接口方法的注解
this.parameterTypes = method.getGenericParameterTypes(); //方法参数类型
this.parameterAnnotationsArray = method.getParameterAnnotations();//方法参数的注解
}
Builder用于获取传入的method注解信息,通过反射获取了方法的注解、方法参数类型、方法参数的注解。
然后,调用RequestFactory.Builder的build方法来解析注解:
RequestFactory build() {
//1.遍历方法的注解,对方法的每个注解调用parseMethodAnnotation方法进行解析
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//2.遍历方法参数的注解,对方法的每个参数调用parseParameter解析,生成ParameterHandler对象
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount]; //每个参数都创建一个ParameterHandler
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
//3.根据Builder创建并返回RequestFactory对象
return new RequestFactory(this);
}
(3)parseMethodAnnotation()方法
对方法的注解进行解析。
private void parseMethodAnnotation(Annotation annotation) {
//GET、POST等请求方法的注解,调用parseHttpMethodAndPath方法进行处理
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) {
//Headers的注解,调用parseHeaders方法进行处理
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) {
//Multipart、FormUrlEncoded注解,主要是在标记变量中进行记录
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;
}
}
(4)parseHttpMethodAndPath()方法
对GET、POST等请求方法的注解进行解析。
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
if (value.isEmpty()) { // 若请求方法的注解(如GET)里面没有写值,则结束
return;
}
// 判断请求方法的注解中的值是否合理,不合理则抛出异常
int question = value.indexOf('?');
if (question != -1 && question < value.length() - 1) {
String queryParams = value.substring(question + 1);
Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);//使用正则表达式匹配
if (queryParamMatcher.find()) {
throw methodError();
}
}
// 记录相对Url;解析并获取注解中的占位符(parsePathParameters方法内部使用了正则表达式)
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
(5)parseHeaders()方法:
对Headers注解进行解析。
private Headers parseHeaders(String[] headers) {
Headers.Builder builder = new Headers.Builder(); // 这是okhttp3的Headers.Builder
for (String header : headers) {
int colon = header.indexOf(':');
String headerName = header.substring(0, colon);// 获取Header名
String headerValue = header.substring(colon + 1).trim();//获取Header值
if ("Content-Type".equalsIgnoreCase( headerName)) { //如果Header是"Content-Type",则会进行一些特殊处理
contentType = MediaType.get(headerValue);
} else {
builder.add(headerName, headerValue); //将Header添加到builder中
}
}
return builder.build(); //返回okhttp3.Headers
}
将传入的字符串数组headers,构造为okhttp3.Headers并返回,对于Content-Type类型的Header,会进行一些特殊的处理。
(6)parseParameter()方法
对方法参数进行解析。
private ParameterHandler<?> parseParameter(int p, Type parameterType, Annotation[] annotations, boolean allowContinuation) { //p:方法参数的位置;parameterType:方法参数的类型;annotations:方法参数的注解;allowContinuation:是否允许为Continuation(通过是否为最后一个参数进行判断)
ParameterHandler<?> result = null;
if (annotations != null) {
// 对该参数的每个注解进行解析
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction = parseParameterAnnotation(p, parameterType, annotations, annotation);
if (annotationAction == null) {
continue;
}
// 一个方法参数最多只能有一个Retrofit注解,多了则抛异常
if (result != null) {
throw parameterError(method, p, "Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction; //记录结果
}
}
return result;
}
使用parseParameterAnnotation解析方法参数的注解,且一个方法参数最多只能有一个Retrofit注解。最终返回result。
parseParameterAnnotation方法会对参数每种类型的注解进行特有的处理,然后返回相应的ParameterHandler。
(7)HttpServiceMethod.parseAnnotations()方法
最后是ServiceMethod的创建。ServiceMethod的创建使用HttpServiceMethod.parseAnnotations方法。HttpServiceMethod类继承了ServiceMethod.
HttpServiceMethod.java:
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
// 检查接口方法的注释,以构造一个使用HTTP的可重用的ServiceMethod。这可能需要代价高昂的反射,所以对于要使用到的ServiceMethod最好只构建一次然后重用它
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(Retrofit retrofit, Method method, RequestFactory requestFactory) {
Annotation[] annotations = method.getAnnotations(); // 获取方法的注解
Type adapterType = method.getGenericReturnType(); // 得到接口方法的返回类型,如Call<User>
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); //创建CallAdapter数据适配器对象。创建retrofit对象时设置了数据适配器工厂,数据适配器对象最终就是通过工厂创建的
Type responseType = callAdapter.responseType(); // 接口方法的实际返回类型,例如Call<User>会返回User
Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter( retrofit, method, responseType); //创建Converter数据解析器对象,数据解析器对象最终就是通过数据解析器工厂创建的
okhttp3.Call.Factory callFactory = retrofit.callFactory;
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); //创建并返回一个CallAdapted对象,CallAdapted继承至HttpServiceMethod
}
//重写ServiceMethod的invoke()方法
@Override final ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<> (requestFactory, args, callFactory, responseConverter); //由上面准备的requestFactory、callFactory、args和responseConverter创建一个OkHttpCall对象,OkHttpCall是个关键的类,网络请求的具体实现就在里边
return adapt(call, args); // adapt()是HttpServiceMethod中的一个抽象方法
}
protected abstract ReturnT adapt( Call<ResponseT> call, Object[] args);
}
如果创建Retrofit对象时设置了RxJava数据适配器工厂、Gson数据解析器工厂,这里就会从工厂中得到对应的数据适配器和数据解析器,最后将它们封装到CallAdapted里。
(8)createCallAdapter()方法
数据适配器CallAdapter用于将retrofit2.Call<R>对象适配为类型为T的对象。查看createCallAdapter方法,看CallAdapter是如何被创建的:
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
}
调用了Retrofit的callAdapter()方法:
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
从可用的factories中返回returnType相应的CallAdapter。
继续看nextCallAdapter()方法:
public CallAdapter<?, ?> nextCallAdapter( CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
int start = callAdapterFactories.indexOf( skipPast) + 1; //从列表开始寻找的位置,这里是从0开始
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this); //若索引处的CallAdapter.Factory可以处理该接口方法,则返回CallAdapter,否则返回null
if (adapter != null) {
return adapter;
}
}
}
该方法会遍历Retrofit的callAdapterFactories,查看是否有可以处理指定的returnType和annotations的CallAdapter.Factory,有则返回该CallAdapter,整个列表都没有找到合适的CallAdapter.Factory,则抛出异常。
(9)createResponseConverter()方法
首先了解一下数据转换器Converter:
Converter是一个接口,用于将类型为F的数据转换为类型T。Converter实例由Converter.Factory创建,Retrofit里面有Converter.Factory的实例。
public interface Converter<F, T> {
T convert(F value) throws IOException;
abstract class Factory {
// 该Factory可以处理type和annotations的接口方法,则返回Converter,否则返回null
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
public Converter<?, String> stringConverter( Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound( index, type);
}
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
Converter.Factory的几个方法:
1)responseBodyConverter:完成ResponseBody到实际的返回类型的转化,实际返回类型例如是Call<User>里面的泛型User。
2)requestBodyConverter:完成对象到RequestBody的构造。
然后看createResponseConverter()如何创建Converter:
private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(Retrofit retrofit, Method method, Type responseType) {
Annotation[] annotations = method.getAnnotations();
return retrofit.responseBodyConverter( responseType, annotations);
}
Retrofit::responseBodyConverter:
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
Retrofit::nextResponseBodyConverter:
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast, Type type, Annotation[] annotations) {
int start = converterFactories.indexOf( skipPast) + 1;//从列表开始寻找的位置,这里是从0开始
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter = converterFactories.get(i).responseBodyConverter(type, annotations, this); //若索引处的Converter.Factory可以处理接口方法,则返回Converter,否则返回null
if (converter != null) {
return (Converter<ResponseBody, T>) converter;
}
}
// 没有获取到适合该接口方法的Converter,则拼接异常信息并抛出异常
}
从converterFactories里获取合适的Converter,和获取CallAdapter的过程类似。
至此,loadServiceMethod()方法的执行流程就结束了,该方法最终返回了一个继承自HttpServiceMethod的CallAdapted对象。同时准备好了OkHttpCall、数据适配器以及数据解析器。
2)第二步 返回CallAdapted对象后, 调用invoke()方法
HttpServiceMethod::parseAnnotations最终会创建并返回一个CallAdapted对象,CallAdapted是HttpServiceMethod的静态内部类,它继承了HttpServiceMethod,并实现了HttpServiceMethod的adapt()方法。
CallAdapted的继承关系:CallAdapted -> HttpServiceMethod -> ServiceMethod
ServiceMethod是一个抽象类,定义如下:
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {...}
// 抽象方法invoke
abstract T invoke(Object[] args);
}
ServiceMethod内部定义了抽象方法invoke,在Retrofit::create动态代理InvocationHandler中,就调用了ServiceMethod的invoke方法。
ServiceMethod的直接子类只有一个,即HttpServiceMethod,它也是一个抽象类:
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
@Override
final ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
protected abstract ReturnT adapt( Call<ResponseT> call, Object[] args);
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {...}
...
}
HttpServiceMethod的大部分方法前面都已经看过了。这里主要关注2点:
1)在invoke方法中,创建了一个OkHttpCall对象,并且调用虚方法adapt对OkHttpCall进行转化,adapt方法在子类中实现。
2)CallAdapted继承至HttpServiceMethod。
注意,HttpServiceMethod重写了父类的invoke方法并标记为final,意味着子类无法重写该方法,又由于ServiceMethod的直接子类只有HttpServiceMethod一个,所以调用ServiceMethod::invoke实际上调用的是HttpServiceMethod::invoke。
CallAdapted定义如下:
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod< ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter, CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter; // callAdapter是刚刚得到的数据适配器
}
@Override protected ReturnT adapt( Call<ResponseT> call, Object[] args) {
// 调用数据适配器的adapt()方法,注意这里的参数call是OkHttpCall类型的
return callAdapter.adapt(call);
}
}
默认情况下,数据适配器CallAdapter由DefaultCallAdapterFactory处理请求:
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
private final Executor callbackExecutor;// 默认情况下,这是一个MainThreadExecutor,可以通过handler将任务调度到主线程中执行
DefaultCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {//get方法会返回一个CallAdapter
// 检查接口方法的返回类型
if (getRawType(returnType) != Call.class) {
return null;
}
if (!(returnType instanceof ParameterizedType)) {
throw new IllegalArgumentException("Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
}
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);// 获取返回类型的泛型参数的上界
final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class) ? null : callbackExecutor; // 判断方法注解是否包含SkipCallbackExecutor.class,一般不包含,所以这里executor的值为callbackExecutor(默认情况下,它是一个MainThreadExecutor)
// 创建并返回CallAdapter
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
//将Call<Object>适配为Call<Object>。通过CallAdapter的adapt方法可以将传入的Call适配包装为一个ExecutorCallbackCall。这个ExecutorCallbackCall实际上就是业务层拿到的Call,可以调用它的enqueue或者execute方法进行网络请求
@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? call : new ExecutorCallbackCall<>(executor, call); // 正常情况下executor不为null,因此call会被适配为一个ExecutorCallbackCall
}
};
}
//ExecutorCallbackCall是DefaultCallAdapterFactory的静态内部类
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate; // OkHttpCall
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override
public void enqueue(final Callback<T> callback) { //callback:业务层传入的Callback
// 调用delegate的enqueue进行请求
delegate.enqueue(new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
// 将回调给业务层的代码,切到主线程中执行
callbackExecutor.execute(() -> {
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(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
@Override
public Response<T> execute() throws IOException {
return delegate.execute();
}
}
}
delegate变量其实是一个OkHttpCall实例。
有两种执行方式:
1)enqueue:异步执行。使用callbackExecutor将给业务层的回调代码切换到主线程中执行。
2)execute:同步执行。
如果创建Retrofit的时候设置了RxJava数据适配器而不是使用默认适配器,这里的adapt方法最终会调用RxJava数据适配器的adapt()方法,参数是OkHttpCall。
RxJava2CallAdapter的adapt()方法:
RxJava2CallAdapter.java:
@Override public Object adapt(Call<R> call) {
Observable<Response<R>> responseObservable = isAsync ? new CallEnqueueObservable<>(call) : new CallExecuteObservable<>(call); // call对象类型是OkHttpCall
Observable<?> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
......
// 返回上边创建的observable对象
return RxJavaPlugins.onAssembly( observable);
}
先执行new CallExecuteObservable<>(call),得到responseObservable对象,再执行new BodyObservable<>(responseObservable),对其进一步封装。最终返回一个Observable对象。
先看CallExecuteObservable类是如何实现的:
final class CallExecuteObservable<T> extends Observable<Response<T>> {
private final Call<T> originalCall;
CallExecuteObservable(Call<T> originalCall) {
this.originalCall = originalCall;
}
// Observable订阅Observer时会执行该方法
@Override protected void subscribeActual( Observer<? super Response<T>> observer) {
Call<T> call = originalCall.clone();
CallDisposable disposable = new CallDisposable(call); //将call对象封装成CallDisposable,以具有取消请求的功能
observer.onSubscribe(disposable);//产生了订阅关系
if (disposable.isDisposed()) {
return;
}
boolean terminated = false;
try {
// call对象类型是OkHttpCall,execute()方法会执行OkHttp的同步网络请求
Response<T> response = call.execute();
if (!disposable.isDisposed()) {
observer.onNext(response); // 将请求结果发送给observer
}
if (!disposable.isDisposed()) {
terminated = true;
observer.onComplete(); //通知observer,请求结果发送结束
}
} catch (Throwable t) {
// 通知observer,在网络请求、发送结果过程中出现了异常
observer.onError(t);
}
}
}
private static final class CallDisposable implements Disposable {
private final Call<?> call;
private volatile boolean disposed;
CallDisposable(Call<?> call) {
this.call = call;
}
@Override public void dispose() {
disposed = true;
call.cancel();
}
@Override public boolean isDisposed() {
return disposed;
}
}
}
CallExecuteObservable类的核心就是subscribeActual()方法,当Observer订阅Observable时会执行该方法,即调用subscribe()方法时。
在subscribeActual()方法里会进行网络请求,并将结果传递给Observer。
那为什么BodyObservable类要对responseObservable进一步封装呢?去里边找找答案:
final class BodyObservable<T> extends Observable<T> {
private final Observable<Response<T>> upstream;
BodyObservable(Observable<Response<T>> upstream) {
this.upstream = upstream;
}
// Observable订阅Observer时会执行该方法
@Override protected void subscribeActual( Observer<? super T> observer) {
// new BodyObserver<T>(observer),将RxJava订阅时,自定义的Observer重新封装
upstream.subscribe(new BodyObserver<T>(observer));
}
private static class BodyObserver<R> implements Observer<Response<R>> {
private final Observer<? super R> observer;
private boolean terminated;
BodyObserver(Observer<? super R> observer) {
this.observer = observer;
}
@Override public void onSubscribe(Disposable disposable) {
observer.onSubscribe(disposable);
}
// 将CallExecuteObservable中,observer.onNext(response)这一步拿到的请求结果进一步处理
@Override public void onNext(Response<R> response) {
// 请求成功
if (response.isSuccessful()) {
// 只将响应体发送给自定义的observer
observer.onNext(response.body());
} else {
terminated = true;
Throwable t = new HttpException(response);
// 将异常信息发送给自定义的Observer
observer.onError(t);
}
}
@Override public void onComplete() {
if (!terminated) {
observer.onComplete();
}
}
@Override public void onError(Throwable throwable) {
if (!terminated) {
observer.onError(throwable);
} else {
......
}
}
}
}
可以看到BodyObservable类的主要作用就是通过BodyObserver类增强自定义的observer功能,使其可以对CallExecuteObservable中observer.onNext(response)拿到的响应结果进一步处理,只取出响应体的数据发送给自定义的observer。
到这里数据适配器的主要任务就结束了,就是为整合RxJava做准备,调用Retrofit封装的OkHttpCall执行网络请求,并将结果发送给observer。
使用Java动态代理的目的就是要拦截被调用的java方法,然后解析这个java方法的注解,最后生成Request由OkHttp发送。
③OkHttp网络请求
在CallExecuteObservable中执行了OkHttpCall的call.execute()方法,即通过OkHttp进行网络请求的。
(1)OkHttpCall的execute()同步请求方法
OkHttpCall.java:
@Override public Response<T> execute() {
okhttp3.Call call;
synchronized (this) {
if(executed) throw new IllegalStateException( "Already executed.");
executed = true;
call = rawCall;
if (call == null) {
call = rawCall = createRawCall(); //创建OkHttp的Call对象
}
}
if (canceled) {
call.cancel();
}
//call.execute()调用OkHttp的同步网络请求方法。然后parseResponse()解析请求结果
return parseResponse(call.execute());
}
(2)OkHttpCall的enqueue()异步请求方法
@Override public void enqueue(final Callback<T> callback) {
okhttp3.Call call;
synchronized (this) {
if(executed) throw new IllegalStateException( "Already executed.");
executed = true;
call = rawCall;
if (call == null) {
call = rawCall = createRawCall(); //创建OkHttp的Call对象
}
}
if(canceled) {
call.cancel();
}
call.enqueue(new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
response = parseResponse( rawResponse); // 使用gson解析返回的数据
callback.onResponse(OkHttpCall.this, response); //先走适配器转换数据,然后走自定义callback
}
@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) {
}
}
});
}
可见,OkHttpCall的execute/enqueue方法内部会构建OkHttp的Call对象并发起网络请求,这样Retrofit就和OkHttp关联上了。
④数据解析器
OkHttpCall的parseResponse()的作用就是使用Gson将响应体的JSON字符串转换成指定对象。
OkHttpCall.java:
Response<T> parseResponse(okhttp3.Response rawResponse) {
ResponseBody rawBody = rawResponse.body();
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody( rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) {
......
}
if (code == 204 || code == 205) {
......
}
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
T body = responseConverter.convert( catchingBody); //通过指定的数据解析器来解析响应体
return Response.success(body, rawResponse); // 返回请求结果
} catch (RuntimeException e) {
}
}
关键的就是responseConverter.convert( catchingBody),responseConverter就是通过配置Retrofit时设置的GsonConverterFactory数据解析器工厂得到的,对应的数据解析器就是GsonRequestBodyConverter。它通过Gson解析响应体,转换成指定类型的对象。如果响应体是加密的,可以在这里先做解密工作,再做Gson解析。
到这里Retrofit的工作原理基本就结束了,Retrofit就是让开发者通过接口注解的形式描述网络请求,然后解析接口,将网络请求封装到OkHttpCall里。数据适配器就是用Retrofit提供的OkHttpCall来组织网络请求,想怎么玩数据适配器自己决定就好了。数据解析器就相对简单了,把网络请求的结果转换成需要的格式。Retrofit、数据适配器、数据解析器,它们之间的职责划分很明确的,几乎没有业务上的耦合,完全是可插拔式的。
Retrofit里用到的方法比较多,注意理清它们的层次关系就好,如下图:

4.Retrofit结合RxJava使用
①首先在build.gradle文件中加入依赖:
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
compile 'io.reactivex2:rxandroid:2.0.1'
②将接口方法的返回值修改为Observable(被观察者):
public interface RetrofitService {
@GET("query")
Observable<PostInfo> getPostInfoRx( @Query("type") String type, @Query("postid") String postid);
}
③在创建Retrofit时添加RxJava支持:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.kuaidi100.com/")
.addConverterFactory( GsonConverterFactory.create())
.addCallAdapterFactory( RxJavaCallAdapterFactory.create()) // 支持RxJava
.build();
④获取被观察者:
RetrofitService service = retrofit.create( RetrofitService.class);
Observable<PostInfo> observable = service.getPostInfoRx("yuantong", "11111111");
⑤订阅:
observable.subscribeOn(Schedulers.io()) // 在子线程中进行Http访问
.observeOn( AndroidSchedulers.mainThread()) // UI线程处理返回接口
.subscribe(new Observer<PostInfo>() {//订阅
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(PostInfo postInfo) {
Log.i("http返回:", postInfo.toString() + "");
}
});
在RxJava中,由于链式调用的影响,是被观察者订阅观察者。
5.Retrofit注解
①请求方法
在网络请求接口方法中,使用@GET注解,说明这是一个GET方法,当然也可以写成HTTP协议中的其他请求方法(比如POST、PUT、DELETE、HEAD等)。
②请求参数
(1)@Query()
@GET("query")
Call<PostInfo> getPostInfo(@Query("type") String type, @Query("postid") String postid);
相当于:
@GET(query?type=type&postid=postid)
Call<PostInfo> getPostInfo(@Query("type") String type, @Query("postid") String postid);
(2)@QueryMap
当参数很多的时候可以使用Map集合:
@GET("query")
Call<Book> getSearchBook(@QueryMap Map<String, String> parameters);
(3)@Path
用于替换url中的某些字段,当url中字段不确定时可以使用:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);
id可以为任意字段,需要和@Path("id")中的字段保持一致,如果需要请求参数,也可以使用@Query拼接:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
(4)@Body
可以使用实体类作为请求体,Retrofit会自动转换:
@POST("users/new")
Call<User> createUser(@Body User user);
(5)@FormUrlEncoded/@Field
用于传送表单数据,注意在头部需要加上@FormUrlEncoded,first_name代表key,first代表value:
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
(6)@Multipart/@Part
用于上传文件:
@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
(7)@Header/@Headers用于设置请求头
以非固定数据的形式添加头信息:
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
以固定数据的形式添加头信息:
@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();
@Headers({
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);
本文详细介绍了Android Retrofit的使用,包括其基于OkHttp的封装如何优化网络请求,如build模式创建网络请求配置、注解接口封装HTTP请求、Gson解析数据以及Executor线程切换。还讲解了Retrofit的用法,如添加依赖、创建Retrofit实例、构建接口、发起同步和异步请求。接着深入源码分析了Retrofit对象的构建、create方法生成代理对象的过程,以及OkHttp网络请求的执行。此外,还探讨了Retrofit与RxJava结合的使用方法以及各种请求参数的注解使用方式。
1033

被折叠的 条评论
为什么被折叠?



