Retrofit 创建网络请求接口实例过程
Retrofit 基本使用
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 实现的。
以上就是Retrofit 创建网络请求接口实例过程的详细内容,更多关于Retrofit 网络请求接口的资料请关注脚本之家其它相关文章!
相关文章
解决Android Studio Gradle Metadata特别慢的问题
这篇文章主要介绍了解决Android Studio Gradle Metadata特别慢的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2020-03-03Android Jetpack架构中ViewModel接口暴露的不合理探究
这篇文章主要介绍了Android Jetpack架构组件 ViewModel详解,ViewModel类让数据可在发生屏幕旋转等配置更改后继续存在,ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据。感兴趣可以来学习一下2022-07-07ImageView的属性android:scaleType的作用分析
本篇文章是对ImageView的属性android:scaleType的作用进行了详细的分析介绍,需要的朋友参考下2013-06-06Android实现仿淘宝购物车增加和减少商品数量功能demo示例
这篇文章主要介绍了Android实现仿淘宝购物车增加和减少商品数量功能,结合实例形式分析了Android实现的淘宝购物车商品数量变换与计算相关技巧,需要的朋友可以参考下2016-07-07Android在一个app中安装并卸载另一个app的示例代码
这篇文章主要介绍了Android在一个app中安装并卸载另一个app的示例代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2021-03-03Android开发中Activity之间切换出现短暂黑屏的解决方法
这篇文章主要介绍了Android开发中Activity之间切换出现短暂黑屏的解决方法,较为详细的分析了Android中Activity之间切换出现短暂黑屏的原因与解决方法,需要的朋友可以参考下2016-02-02
最新评论