Retrofit (2.9.0) 的使用及源码分析
文章目录
- 一、Retrofit 是什么?
- 二、使用步骤(Android代码)
- 1.引入库
- 2.创建Retrofit实例
- 3.创建ApiService接口
- 4.进行网络请求
- 三、源码分析
- 1.动态代理获取ApiService接口实例
- 2.接口方法的解析、获取
- 3.接口的调用
- 总结
一、Retrofit 是什么?
Github的原文是:A type-safe HTTP client for Android and the JVM. 一个适用于Android和JVM的类型安全的HTTP客户端。
在我看来是一个基于OkHttp,通过运用注解和动态代理的方法,实现网络请求的框架。
二、使用步骤(Android代码)
1.引入库
//retrofit版本
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
//retrofit的数据适配器,支持Gson、jackson、java8、scalar等等,也可以自定义
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
//retrofit的请求适配器,支持java8、rxjava1、rxjava2、rxjava3等等,也可以自定义
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'
2.创建Retrofit实例
//配置OkHttpClient,可以参考OkHttp的教程配置项目中需要的功能
private val client by lazy {OkHttpClient.Builder().build()
}//配置Retrofit
private val retrofit by lazy {Retrofit.Builder()//配置baseUrl,可以通过反射等方式动态修改.baseUrl("https://www.wanandroid.com/") //配置OkHttpClient客户端.client(client)//添加数据适配器工厂,如果不添加,默认工厂是BuiltInConverters(只能处理ResponseBody、Void、Unit类型)//如果是Java8+/Android API 24+ 还有一个OptionalConverterFactory.addConverterFactory(GsonConverterFactory.create())//添加请求适配器工厂,如果不添加,默认工厂是DefaultCallAdapterFactory(处理Call类型)//如果是Java8+/Android API 24+ 还有一个CompletableFutureCallAdapterFactory.addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build()
}
3.创建ApiService接口
interface WanAndroidApi {@GET("article/list/{page}/json")fun getHomeArticles(@Path("page") page: Int): Call<ArticleData> //默认请求方式@GET("banner/json")fun getBanners(): Observable<Response<BannerData>> //基于rxjava2方式,也可以把Response去掉,直接用Observable @GET("hotkey/json")suspend fun getHotkeys(): HotkeyData //基于Kotlin协程 挂起函数
}
4.进行网络请求
// 通过动态代理获取接口实例
val wanAndroidApi = retrofit.create(WanAndroidApi::class.java)// 默认请求方式
val articleDataCall = wanAndroidApi.getHomeArticles(1)
articleDataCall.enqueue(object : Callback<ArticleData> {override fun onResponse(call: Call<ArticleData>, response: Response<ArticleData>) {//获得response对象,返回内容为response.body()}override fun onFailure(call: Call<ArticleData>, t: Throwable) {}
})
// 基于rxjava2请求方式
wanAndroidApi.getBanners().subscribeOn(Schedulers.newThread()).subscribe { response ->//获得response对象,返回内容为response.body()}
// 基于Kotlin协程请求方式
GlobalScope.launch {val hotkeyData = wanAndroidApi.getHotkeys() //获得HotKeyData对象
}
三、源码分析
1.动态代理获取ApiService接口实例
从demo中可以看到ApiService接口是通过Retrofit的create()方法获取的,使用的是Java中动态代理的方法,通过Proxy.newProxyInstance动态获取
Retrofit.class//获取ApiService实例
public <T> T create(final Class<T> service) {//检查service是否为Interface以及service及其父接口是否有泛型validateServiceInterface(service); //动态代理返回接口对象return (T)Proxy.newProxyInstance(service.getClassLoader(),new Class<?>[] {service},new InvocationHandler() {、//获取平台信息,此处获取的是Android平台,Platform中定义了一些默认值和方法,如默认的CallAdapterFactory、//ConverterFactory、CallBackExecutor,还有处理接口default方法的方法private final Platform platform = Platform.get(); private final Object[] emptyArgs = new Object[0];//接口方法的调用@Overridepublic @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;// 判断接口里定义的方法是否是default方法,如果是,按照default实现的内容调用,否则,// 调用loadServiceMethod().invoke(),其中loadServiceMethod()是获取方法// 从Java8开始支持接口中定义default方法和static方法return platform.isDefaultMethod(method)? platform.invokeDefaultMethod(method, service, proxy, args): loadServiceMethod(method).invoke(args);}});
}//获取接口方法,此处对接口的方法做了一个缓存,为了确保线程安全,使用ConcurrentHashMap来存储
ServiceMethod<?> loadServiceMethod(Method method) {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;
}
2.接口方法的解析、获取
ServiceMethod 是一个抽象类,用来获取解析Retrofit中定义的注解,组合成方法,通过抽象方法invoke(),返回接口方法的调用,实现类为HttpServiceMethod
abstract class ServiceMethod<T> {static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {//获取请求信息工厂类RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);......//转给子类HttpServiceMethod获取return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);}//调用接口定义的方法,由子类HttpServiceMethod实现,其实就是调用OkHttp进行网络请求abstract @Nullable T invoke(Object[] args);
}
先看RequestFactory如何获取
RequestFactory.classstatic RequestFactory parseAnnotations(Retrofit retrofit, Method method) {//通过建造者模式返回了RequestFactory对象return new Builder(retrofit, method).build();
}
RequestFactory的内部类Builder.classRequestFactory build() {for (Annotation annotation : methodAnnotations) {//解析方法的注解信息parseMethodAnnotation(annotation);}...... int parameterCount = parameterAnnotationsArray.length;parameterHandlers = new ParameterHandler<?>[parameterCount];for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {//解析参数的注解信息parameterHandlers[p] =parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);}...... return new RequestFactory(this);
}//解析附加在方法上的注解信息,获取请求方式、路径、Header、
private void parseMethodAnnotation(Annotation annotation) {if (annotation instanceof DELETE) {parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);} else if (annotation instanceof GET) {parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);} else ......
}//解析参数的注解信息,存储到ParameterHandler中
private @Nullable ParameterHandler<?> parseParameter(int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {ParameterHandler<?> result = null;if (annotations != null) {for (Annotation annotation : annotations) {ParameterHandler<?> annotationAction =parseParameterAnnotation(p, parameterType, annotations, annotation);......}}......//判断是否是协程方法 挂起函数if (Utils.getRawType(parameterType) == Continuation.class) {isKotlinSuspendFunction = true;return null;}......}return result;
}
通过RequestFactory.Builder类实现了RequestFactory各个属性的赋值。然后我们看HttpServiceMethod怎么获取接口方法的。
HttpServiceMethod.class//这里解释一下ResponseT和ReturnT,以Call为例 //ReturnT是Call,ResponseT为ArticleData static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(Retrofit retrofit, Method method, RequestFactory requestFactory) {boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;boolean continuationWantsResponse = false;boolean continuationBodyNullable = false;//获取方法的ReturnTypeAnnotation[] annotations = method.getAnnotations();Type adapterType;//区分是否为Kotlin协程if (isKotlinSuspendFunction) {Type[] parameterTypes = method.getGenericParameterTypes();Type responseType =Utils.getParameterLowerBound(0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {// Unwrap the actual body type from Response. responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);continuationWantsResponse = true;} else {}adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);} else {adapterType = method.getGenericReturnType();}//获取请求适配器,通过adapterType,也就是返回类型,//去最开始添加的CallAdaperFactory的数组中匹配对应的CallAdapter,如Observable对应RxJava2CallAdapter CallAdapter<ResponseT, ReturnT> callAdapter =createCallAdapter(retrofit, method, adapterType, annotations);Type responseType = callAdapter.responseType();......//获取response数据转换器,通过responseType,去最开始添加的ConverterFactory的数组中匹配对应的Converter//如我们添加的GsonConverterConverter<ResponseBody, ResponseT> responseConverter =createResponseConverter(retrofit, method, responseType);okhttp3.Call.Factory callFactory = retrofit.callFactory;//通过之前获取的requestFactory,callFactory,responseConverter,callAdapter 四个值//获取接口的方法,此处HttpServiceMethod细分了3个子类型if (!isKotlinSuspendFunction) { // 非Ktolin协程方式return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);} else if (continuationWantsResponse) { //协程带Response类型//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>) //协程只返回Body类型new SuspendForBody<>(requestFactory,callFactory,responseConverter,(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,continuationBodyNullable);}}
至此,接口方法的获取已经解释清楚了。
3.接口的调用
获取到接口方法后,当我们通过ApiService的实力去调用方法时,如wanAndroidApi.getHomeArticles(1).enqueue(…),就会调用我们获取的ServiceMethod对象的invoke方法,即HttpServiceMethod的invoke方法
HttpServiceMethod.classHttpServiceMethod(RequestFactory requestFactory,okhttp3.Call.Factory callFactory,Converter<ResponseBody, ResponseT> responseConverter) {this.requestFactory = requestFactory;this.callFactory = callFactory;this.responseConverter = responseConverter;}@Overridefinal @Nullable ReturnT invoke(Object[] args) {Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);return adapt(call, args);}protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
可以看到,这里生成了一个OkHttpCall对象,是Retrofit的Call接口的实现类,然后通过抽象的adapt方法进行适配,即交给3个子类CallAdapted
CallAdapted.class@Overrideprotected ReturnT adapt(Call<ResponseT> call, Object[] args) {return callAdapter.adapt(call);}
然后发现又转给了CallAdapter去实现,以我们的第一个接口为例,ReturnType是Call,对应的CallAdapter是由DefaultCallAdapterFactory的get方法生成的,如下:
DefaultCallAdapterFactory.class@Nullablepublic CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {if (getRawType(returnType) != Call.class) {return null;} else if (!(returnType instanceof ParameterizedType)) {throw new IllegalArgumentException("Call return type must be parameterized as Call or Call extends Foo>" );} else {final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType)returnType);final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class) ? null : this.callbackExecutor;//返回CallAdapter实例return new CallAdapter<Object, Call<?>>() {public Type responseType() {return responseType;}public Call<Object> adapt(Call<Object> call) {//此处使用代理模式,将OkHttpCall功能代理到了ExecutorCallbackCall类中。return (Call)(executor == null ? call : new ExecutorCallbackCall(executor, call));}};}}
所以,当我们调用wanAndroidApi.getHomeArticles(1).enqueue(…)时,其实最后是走到了ExecutorCallbackCall的enqueue(…)方法。
ExecutorCallbackCall.class//异步请求public void enqueue(final Callback<T> callback) {Objects.requireNonNull(callback, "callback == null");//此处的delegate其实是OkHttpCallthis.delegate.enqueue(new Callback<T>() {public void onResponse(Call<T> call, Response<T> response) {//通过配置的callbackExecutor将线程切回到MainThreadExecutorCallbackCall.this.callbackExecutor.execute(() -> {if (ExecutorCallbackCall.this.delegate.isCanceled()) {//此处的callback就是我们调用wanAndroidApi.getHomeArticles(1).enqueue(...)时传入的callbackcallback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));} else {callback.onResponse(ExecutorCallbackCall.this, response);}});}public void onFailure(Call<T> call, Throwable t) {ExecutorCallbackCall.this.callbackExecutor.execute(() -> {callback.onFailure(ExecutorCallbackCall.this, t);});}});}
当然,此处只是针对Call这种默认的请求方式来解释源码,我们添加的Rxjava2CallAdapter或者其他的CallAdapter会有各自的adapt方法去实现请求,但都是代理了OkHttpCall去实现网络请求的。而OkHttpCall里其实是封装了OkHttp去进行的请求。
OkHttpCall.class//生成最终网络请求对象其实是okhttp3.Callprivate okhttp3.Call createRawCall() throws IOException {okhttp3.Call call = callFactory.newCall(requestFactory.create(args));//通过RequestFactory生成OkHttp的Requestif (call == null) {throw new NullPointerException("Call.Factory returned null.");}return call;}
当我们配置了Converter后,OkHttpCall中会通过Converter转换成我们需要的Response
OkHttpCall.class//解析OkHttp访问接口返回的数据Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {ResponseBody rawBody = rawResponse.body();......ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);try {//通过我们设置的Converter提供的responseConverter去转换返回数据,返回我们需要的类型T body = responseConverter.convert(catchingBody);return Response.success(body, rawResponse);} catch (RuntimeException e) {......}}
至此,我们完成了对Retrofit框架的源码解析。
根据对源码的解析我们发现这个框架的重中之重就是CallAdapter的adapt(),这是真正实现网络请求的关键点。
总结
根据源码分析,总结一下Retrofit中使用的设计模式吧,对我们以后设计代码也有所帮助。
- 构造者模式(Builder) : 例如Retrofit的Builder。
我们通过链式调用和步骤化的方式创建复杂对象。该模式将对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。 - 抽象工厂模式:例如CallAdapter.Factory。
通常用于创建一组相关或依赖的对象,这些对象共同完成一项任务或工作。通过使用抽象工厂模式,可以确保创建的对象家族在逻辑上是一致的,并且能够相互协作。 - 适配器模式:例如CallAdapter
用于解决两个不兼容接口之间的兼容性问题。适配器模式将一个类的接口转换成客户端所期望的另一个接口,从而使得原本由于接口不兼容而无法在一起工作的类能够协同工作。 - 代理模式:例如ExecutorCallbackCall
可以用来控制对对象的访问、提供额外的功能、保护真实对象
以上内容属于个人见解,如有不对请留言指正,谢谢。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
