Retrofit 创建网络请求接口实例过程
阿健叔 人气:0Retrofit 基本使用
implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
interface NetApi { @GET("/hotkey/json") fun getHotKey(): Call<Response> companion object { private const val BASE_URL = "https://www.wanandroid.com/" fun createApi(): NetApi = Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()) .build().create(NetApi::class.java) } } data class HotWords( val id: String, val name: String, ) data class Response( val errorCode: Int, val errorMsg: String, val data: List<HotWords> )
NetApi.createApi().getHotKey().enqueue(object : Callback<Response> { override fun onResponse(call: Call<Response>, response: retrofit2.Response<Response>) { Log.i(tag, "onResponse: ${response.body()?.data}") } override fun onFailure(call: Call<Response>, t: Throwable) { Log.i(tag, "onFailure: ${t.message}") } })
这样一个基本的网络请求就搞定了,使用很简洁,正是因为其内部使用了大量的设计模式和优秀的架构设计,才得以使其如此方便地进行网络请求,下面来一起瞧瞧 Retrofit 的源码吧~
Retrofit构建过程
使用了建造者模式通过内部静态类 Builder 构建一个 Retrofit 实例,这里列出了部分方法,其他类似。
public static final class Builder { private final Platform platform; // 网络请求工厂,工厂方法模式 private @Nullable okhttp3.Call.Factory callFactory; // 网络请求地址 private @Nullable HttpUrl baseUrl; // 数据转换器工厂的集合 private final List<Converter.Factory> converterFactories = new ArrayList<>(); // 网络请求适配器工厂的集合,默认是 ExecutorCallAdapterFactory private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(); // 回调方法执行器,用于切换线程 private @Nullable Executor callbackExecutor; // 一个开关,为 true 则会缓存创建的 ServiceMethod private boolean validateEagerly; ... public Builder baseUrl(String baseUrl) { Objects.requireNonNull(baseUrl, "baseUrl == null"); return baseUrl(HttpUrl.get(baseUrl)); } public Builder baseUrl(HttpUrl baseUrl) { Objects.requireNonNull(baseUrl, "baseUrl == null"); List<String> pathSegments = baseUrl.pathSegments(); if (!"".equals(pathSegments.get(pathSegments.size() - 1))) { throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl); } this.baseUrl = baseUrl; return this; } // 将一个含有 Gson 对象实例的 GsonConverterFactory 放入数据转换器工厂 public Builder addConverterFactory(Converter.Factory factory) { converterFactories.add(Objects.requireNonNull(factory, "factory == null")); return this; } ... }
通过 build,我们上面 Builder 类中的参数对象都配置到了 Retrofit 对象中。
public Retrofit build() { if (baseUrl == null) { throw new IllegalStateException("Base URL required."); } okhttp3.Call.Factory callFactory = this.callFactory; if (callFactory == null) { callFactory = new OkHttpClient(); } 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)); // Make a defensive copy of the converters. List<Converter.Factory> converterFactories = new ArrayList<>( 1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize()); // Add the built-in converter factory first. This prevents overriding its behavior but also // ensures correct behavior when using converters that consume all types. converterFactories.add(new BuiltInConverters()); converterFactories.addAll(this.converterFactories); converterFactories.addAll(platform.defaultConverterFactories()); return new Retrofit( callFactory, baseUrl, unmodifiableList(converterFactories), unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly); }
创建网络请求接口实例过程
使用动态代理的方式拿到所有注解配置后,创建网络请求接口实例。
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); } args = args != null ? args : emptyArgs; return platform.isDefaultMethod(method) ? platform.invokeDefaultMethod(method, service, proxy, args) : loadServiceMethod(method).invoke(args); } }); }
跟踪 loadServiceMethod
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; }
parseAnnotations 解析注解配置得到 ServiceMethod,然后加入到 serviceMethodCache 缓存中,是一个 ConcurrentHashMap 。
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,主要用于后续创建 OkHttp 请求所需要的 Request 对象。那后面的 HttpServiceMethod.parseAnnotations 又是干什么的呢?往下看。
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) { ... okhttp3.Call.Factory callFactory = retrofit.callFactory; if (!isKotlinSuspendFunction) { return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); } else if (continuationWantsResponse) { //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object. return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>( requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter); } else { //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object. return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>( requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter, continuationBodyNullable); } }
如果不是 kotlin suspend 函数,使用 CallAdapted 类,如果是 kotlin suspend 函数返回类型是 Response,则使用 SuspendForResponse 类,其余情况使用 SuspendForBody,如 suspend 函数返回类型不是 Response 。一般情况下,我们使用的基本上是属于其余情况,我们来看下 SuspendForBody 类
static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> { private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter; private final boolean isNullable; ... @Override protected Object adapt(Call<ResponseT> call, Object[] args) { call = callAdapter.adapt(call); Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1]; try { return isNullable ? KotlinExtensions.awaitNullable(call, continuation) : KotlinExtensions.await(call, continuation); } catch (Exception e) { return KotlinExtensions.suspendAndThrow(e, continuation); } } }
跟进 KotlinExtensions.awaitNullable,我们可以看到 SuspendForBody 会将 Response.body 作为协程挂起点的返回值。
suspend fun <T : Any> Call<T?>.await(): T? { return suspendCancellableCoroutine { continuation -> //协程取消是调用 cancel continuation.invokeOnCancellation { cancel() } enqueue(object : Callback<T?> { override fun onResponse(call: Call<T?>, response: Response<T?>) { if (response.isSuccessful) { //继续执行相应的协程,将 response.body 作为最后一个挂起点的返回值。 continuation.resume(response.body()) } else { continuation.resumeWithException(HttpException(response)) } } override fun onFailure(call: Call<T?>, t: Throwable) { continuation.resumeWithException(t) } }) } }
执行请求过程
public void enqueue(final Callback<T> callback) { Objects.requireNonNull(callback, "callback == null"); 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 { // 创建 OkHttp 的 Call 对象 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 } } }); }
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException { ResponseBody rawBody = rawResponse.body(); // Remove the body's source (the only stateful object) so we can pass the response along. rawResponse = rawResponse .newBuilder() .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())) .build(); int code = rawResponse.code(); // 根据响应返回的状态码进行处理 if (code < 200 || code >= 300) { try { // Buffer the entire body to avoid future I/O. 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); } //包装 RequestBody ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody); try { // 将响应体转为 Java 对象 T body = responseConverter.convert(catchingBody); return Response.success(body, rawResponse); } catch (RuntimeException e) { // If the underlying source threw an exception, propagate that rather than indicating it was // a runtime exception. catchingBody.throwIfCaught(); throw e; } }
总结
使用建造者模式通过 Builder 构建一个 Retrofit 实例,Builder 类中的参数对象都配置到 Retrofit 对象中,然后使用 JDK 动态代理的方式拿到所有注解配置后,创建网络请求接口实例,生成 OkHttp 请求,通过 CallAdapterFactory 找到对应的执行器,比如 RxJava2CallAdapterFactory,通过 ConverterFactory 将返回数据解析成 JavaBean,使用者只需关心请求参数,内部实现由 Retrofit 封装完成,底层请求还是基于 Okhttp 实现的。
加载全部内容