
版本号:2.5.0
一.基本使用
1.定义请求接口
interface GithubService { //通过注解定义请求的方法以及路径,“{}”里面的表示:该内容是可变的,通过下面方法的参数赋值
@GET("users/{user}/repos") fun listRepos(@Path("user") user: String): Call<Any>
}2.创建Retrofit对象,通过Call对象发送网络请求
//创建Retrofit对象val retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())//设置数据解析器
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//设置支持Rxjava平台
.build()//创建网络请求接口实例val githubService = retrofit.create(GithubService::class.java)
//调用相应的接口获取对应的call对象val call = githubService.listRepos("user")//通过call对象执行异步请求call.enqueue(object : Callback<Any> { override fun onFailure(call: Call<Any>, t: Throwable) { } override fun onResponse(call: Call<Any>, response: Response<Any>) { }
})通过上面的代码可以看出,真正发送网络请求的是Call对象,也就是Okhttp,Retrofit只是对网络请求参数的封装,真正的请求是通过Okhttp完成的。
应用通过Retrofit发送网络请求,实际上是使用Retrofit接口层封装请求参数,之后由Okhttp完成后续的请求操作,在服务端返回数据之后,Okhttp将原始的结果交给Retrofit,Retrofit根据用户的需求对结果进行解析。
Okhttp源码分析
二.源码分析
1.创建对象
网络请求参数的封装是通过Retrofit完成的,所以先看一下给对象的创建代码:
Retrofit.Builder()
public static final class Builder { //Retrofit支持平台
private final Platform platform; //网路请求的okhttp的工厂,默认就是OkhttpClient
private @Nullable okhttp3.Call.Factory callFactory; //请求的基地址
private @Nullable HttpUrl baseUrl; //数据转换器工厂集合;数据转换器就是将从网络获取的数据转成java对象
private final List<Converter.Factory> converterFactories = new ArrayList<>(); //适配器工厂集合;适配器工厂:将我们Call对象转换成其他类型能用的请求,比如:Rxjava
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(); //用于执行异步回调的,在Android是默认在主线程中回调
private @Nullable Executor callbackExecutor; //标志位,用于后面是否立即解析方法参数
private boolean validateEagerly;
Builder(Platform platform) { this.platform = platform;
} public Builder() { this(Platform.get());
} public Retrofit build() { if (baseUrl == null) { throw new IllegalStateException("Base URL required.");
} //其他的成员变量判断
...... //创建Retrofit对象,该对象中也有对应的成员变量,除了platform
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
}重点关注一下成员变量,如注释所示。在上述代码中
Builder()会调用Builder(Platform platform)传入一个Platform对象,下面看一个该对象创建的代码:Platform.get()
class Platform { private static final Platform PLATFORM = findPlatform(); static Platform get() { return PLATFORM;
} private static Platform findPlatform() { try { //加载指定的类
Class.forName("android.os.Build"); //如果Build.VERSION.SDK_INT != 0,说明是Android平台
if (Build.VERSION.SDK_INT != 0) { return new Android();
}
} ...... try {
Class.forName("java.util.Optional"); return new Java8();
}...... return new Platform();
}从上述代码可以看出,Retrofit支持Android和Java8平台。这里我们只关注Android平台,下面看一下Android中做了什么。
static class Android extends Platform {
...... @Override public Executor defaultCallbackExecutor() { return new MainThreadExecutor();
} @Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories( @Nullable Executor callbackExecutor) { if (callbackExecutor == null) throw new AssertionError();
ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor); return Build.VERSION.SDK_INT >= 24
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
...... @Override List<? extends Converter.Factory> defaultConverterFactories() { return Build.VERSION.SDK_INT >= 24
? singletonList(OptionalConverterFactory.INSTANCE)
: Collections.<Converter.Factory>emptyList();
}
...... static class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) {
handler.post(r);
}
}
}Android中提供了默认的Executor、ConverterFactor和CallAdapterFactory,其中默认的异步异步回调处理是在AndroidUI线程处理的
new Handler(Looper.getMainLooper());,这也就是为什么Retrofit网络请求回调是在主线程中执行的(Okhttp的回调是在子线程中执行的)
2.参数设置
baseUrl()
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null"); //HttpUrl对baseUrl进行解析分段,如获取:scheme、host、port和PathSegments
return baseUrl(HttpUrl.get(baseUrl));
}public Builder baseUrl(HttpUrl baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments(); //baseUrl的必须以“/”结尾
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) { throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
} this.baseUrl = baseUrl; return this;
}注意:baseUrl的必须以“/”结尾,否则抛出异常IllegalArgumentException(baseUrl must end in /:)
addConverterFactory()
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null")); return this;
}该方法很简单,就是把设置的工厂添加到对应的集合中,重点看一下Converter.Factory对象的创建:
GsonConverterFactory.create():
public static GsonConverterFactory create() { return create(new Gson());
}public static GsonConverterFactory create(Gson gson) { if (gson == null) throw new NullPointerException("gson == null"); return new GsonConverterFactory(gson);
}private GsonConverterFactory(Gson gson) { this.gson = gson;
}创建的过程就是创建一个Gson对象,然后给GsonConverterFactory的属性
gson赋值。
addCallAdapterFactory()
该方法同
addConverterFactory()类似,将Factory对象添加到相应的集合中。RxJava2CallAdapterFactory.create()方法也类似,创建一个RxJava的Scheduler对象并赋值。
3.获取请求接口实例
retrofit.create(GithubService::class.java)
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() { private final Platform platform = Platform.get(); private final Object[] emptyArgs = new Object[0]; //proxy:代理对象
//method:调用的方法信息
//args:调用方法的参数
//当代理对象方法调用的时候就会调用该方法
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable { // 如果调用的是Object类中的方法,比如:toString()方法等
if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args);
} //如果是平台默认的方法,Android平台该方法返回false,所以if条件不成立。
if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args);
} //最终会调用该方法
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}在Android平台下调用请求方法时,是通过动态代理来实现的,在这个过程中最终会调用
loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
我们先看一下loadServiceMethod(method)方法
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;
}
loadServiceMethod方法就是返回了一个ServiceMethod对象,该对象是对请求方法method的封装,如果缓存中存在就从缓存中获取,否则直接创建一个:ServiceMethod.parseAnnotations(this, method);。ServiceMethod是一个抽象类,调用的是它子类HttpServiceMethod的parseAnnotations方法,在该方法中直接new HttpServiceMethod对象,下面就看一下该类中的相关属性和方法:
final class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
...... //请求工厂,里面封装着请求方法先关的信息
private final RequestFactory requestFactory; //请求工厂:其实就是OkhttpClient
private final okhttp3.Call.Factory callFactory; private final CallAdapter<ResponseT, ReturnT> callAdapter; private final Converter<ResponseBody, ResponseT> responseConverter;
...... @Override ReturnT invoke(Object[] args) { return callAdapter.adapt( new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}
}下面重点看一下RequestFactory:
final class RequestFactory {
...... private final Method method; private final HttpUrl baseUrl; final String httpMethod; private final @Nullable String relativeUrl; 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;
......
}从RequestFactory的成员变量可以看出该类中包括请求相关的所有信息。
创建好ServiceMethod对象以后,调用该对象的invoke方法:
@Override ReturnT invoke(Object[] args) { return callAdapter.adapt( new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}该方法就会返回一个Call对象,
allAdapter.adapt()方法就是将OkHttpCall对象转换成其他平台能用的Call对象,比如:RxJava。这里返回的是OkHttpCall的对象,该类是Retrofit中定义的,是对Okhttp中的Call对象的封装。下面看一下该类中的相关属性和方法:
final class OkHttpCall<T> implements Call<T> { private final RequestFactory requestFactory; private final Object[] args; private final okhttp3.Call.Factory callFactory; private final Converter<ResponseBody, T> responseConverter; private volatile boolean canceled; @GuardedBy("this") private @Nullable okhttp3.Call rawCall;
...... //异步请求方法
@Override public void enqueue(final Callback<T> callback) {
......
okhttp3.Call 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();
}......
}
}
...... //调用Okhttp-》call的enqueue方法,完成网络请求
call.enqueue(new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response; try { //解析响应数据
response = parseResponse(rawResponse);
}......
}
}
...... //创建Call对象:okHttpClient.newCall(request)
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
...... return call;
} Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build(); int code = rawResponse.code(); //code判断
if (code < 200 || code >= 300) { try {
ResponseBody bufferedBody = Utils.buffer(rawBody); return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
} if (code == 204 || code == 205) {
rawBody.close(); return Response.success(null, rawResponse);
}
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody); try { //转换成实体类
T body = responseConverter.convert(catchingBody); return Response.success(body, rawResponse);
}......
}
}OkHttpCall对Okhttp的Call封装了一下,它里面的
enqueue方法其实调用的就Call.enqueue,在它的回调成功方法中,通过配置的Converter.Factory将响应数据转换成对应的实体类(Java对象)。还有一个需要关注的地方就是,Requst的创建,是通过requestFactory.create(args)创建的,下面看一下该方法:
final class RequestFactory {
......
okhttp3.Request create(Object[] args) throws IOException { @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
//方法参数解析器,解析接口中定义的方法
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers; //调用方法传入的参数
int argumentCount = args.length; if (argumentCount != handlers.length) { throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
} //通过Builder模式创建Request对象
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
headers, contentType, hasBody, isFormEncoded, isMultipart);
List<Object> argumentList = new ArrayList<>(argumentCount); //设置请求参数
for (int p = 0; p < argumentCount; p++) {
argumentList.add(args[p]);
handlers[p].apply(requestBuilder, args[p]);
} return requestBuilder.get()
.tag(Invocation.class, new Invocation(method, argumentList))
.build();
}
......
}该方法就是根据ParameterHandler解析的参数以及传入的参数值args创建Request对象。
总结
在调用Retrofit的create方法获取接口请求实例Call对象,内部使用的是动态代理的方式,在调用相应的网络请求方法的时候,会回调invoke方法,在该方法中会调用ServiceMethod()的invoke方法。
ServiceMethod是一个抽象类,实际使用的是HttpServiceMethod,该类是对请求方法信息的封装,里面有几个比较重要的成员变量:
1.RequestFactory :包含请求相关的信息
private final Method method; private final HttpUrl baseUrl; final String httpMethod; private final @Nullable String relativeUrl; 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;
2.okhttp3.Call.Factory
3.callAdapter
4.responseConverter
作者:慕涵盛华
链接:https://www.jianshu.com/p/8c6cdf981ae3
随时随地看视频