版本号: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