详解Retrofit源码在请求时使用动态代理模式、工厂模式、静态代理模式、外观模式和对请求结果进行线程切换

我们知道,Retrofit进行网络请求的工作本质是由OkHttp完成的,而Retrofit负债网络请求接口的封装。本文详解Retrofit源码在请求时使用的动态代理模式、工厂模式、静态代理模式、外观模式和对请求结果进行线程切换。
我们使用Retrofit的方式如下:
在这里插入图片描述

1、动态代理模式:

看Retrofit的create方法:
在这里插入图片描述
可知,该方法返回一个通过Proxy.newProxyInstance()创建的动态代理对象wanAndroidService,而调用动态代理对象wanAndroidService的getProjectArticle(1, 1)会调用invoke方法。
看loadServiceMethod方法:
在这里插入图片描述
在这里插入图片描述
Annotation[] methodAnnotations、Type[] parameterTypes和 Annotation[][] parameterAnnotationsArray分别是方法的注解,方法的参数类型,方法参数注解的数组。
在这里插入图片描述

parseMethodAnnotation()方法就是解析方法的注解:
在这里插入图片描述
反射耗性能,也就是new ServiceMethod.Builder(this.method)耗性能,那么Retrofit是如何解决这个反射带来的性能问题的?答案是缓存,也就是将实例化得到的ServiceMethod对象缓存起来:
在这里插入图片描述
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
而且用于缓存的容器还是个使用了LRU算法的LinkedHashMap。

2、工厂模式:

再看前面截图中Retrofit的第561行build()方法里,adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor))
是,platform的defaultCallAdapterFactory方法返回ExecutorCallAdapterFactory对象,所以platform.defaultCallAdapterFactory(callbackExecutor)是把callbackExecutor传入ExecutorCallAdapterFactory的构造方法,将实例化得到的ExecutorCallAdapterFactory对象存入List<CallAdapter.Factory> adapterFactories,然后把adapterFactories 传入Retrofit的构造方法,从而称为Retrofit的成员变量。

ExecutorCallAdapterFactory如下:
在这里插入图片描述
它本身是Factory的子类,这个工厂是通过get方法来生产它的产品—CallAdapter对象,CallAdapter有个adapt的方法,通过这个adapt方法可返回一个ExecutorCallbackCall对象来。

3、静态代理模式

先说结论:前述的ExecutorCallbackCall是OkhttpCall的代理类(下面有详细分析),用户调用生成的动态代理对象wanAndroidService的getProjectArticle(1,1)方法返回的就是ExecutorCallbackCall这个Call对象,然后用户再调用该对象的enqueue方法,该方法会调用OkhttpCall的enqueue方法,在OkhttpCall的enqueue方法里通过外观模式调用Okhttp的相应方法从而进入网络请求的流程。现在论证这个结论:

在这里插入图片描述
用户调用wanAndroidService.getProjectArticle(1, 1)就会执行InvocationHandler的invoke方法,执行return serviceMethod.callAdapter.adapt(okHttpCall)并且,其中serviceMethod.callAdapter会调用到Rrtrofit的CallAdapter<?> nextCallAdapter(…)方法:
在这里插入图片描述
其实就是通过前述的ExecutorCallAdapterFactory的get方法来生产一个CallAdapter对象产品,所以,serviceMethod.callAdapter.adapt(okHttpCall)其实是调用CallAdapter的adapt方法返回了一个OkhttpCall的代理对象—ExecutorCallbackCall对象。
在这里插入图片描述
注意这个adapt方法把OkhttpCall对象转入ExecutorCallbackCall的构造方法,而OkhttpCall和ExecutorCallbackCall都实现了Call接口,所以ExecutorCallbackCall是OkhttpCall的静态代理类。用户调用projectArticle.enqueue其实就是执行ExecutorCallbackCall对象的enqueue方法:
在这里插入图片描述
第75行的delegate.enqueue就是通过静态代理调用OkhttpCall的queue方法(下面有详述),然后第77行就是转换成主线程。

4、外观模式

先看OkHttpCall的queue方法:

 @Override public void enqueue(final Callback<T> callback) {
    if (callback == null) throw new NullPointerException("callback == null");
    **//声明okhttp3.Call call变量
    okhttp3.Call call;**
    Throwable failure;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;
      ...
      if (call == null && failure == null) {
        try {
          **//得到okhttp3.Call call对象
          call = rawCall = createRawCall();**
        } catch (Throwable t) {
          failure = creationFailure = t;
        }
      }
    }

    ...
    **call.enqueue(new okhttp3.Callback()** {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
       ...
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
       ...
      }
      ...
      }
    });
  }

可知,在OkhttpCall类中的enqueue方法中,创建个okhttp3.Call call对象。然后call.enqueue(new okhttp3.Callback() {…})
所以很明显,这里封装okhttp,即调用okhttp3.Call对象的enqueue方法进行请求,这是外观设计模式。

5、对请求的结果切换到主线程进行处理:
在这里插入图片描述
在Retrofit类的build()函数中,使用了看似是线程池的东西,来看这个platform是什么,已经它的defaultCallbackExecutor()方法如何返回callbackExecutor:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可知,执行defaultCallbackExecutor()方法可得到实现了Executor接口的MainThreadExecutor对象,执行该对象的execute方法,就是执行Main线程的handler的post方法,从而可以达到子线程切换到主线程。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
首先,需要添加 Retrofit 和 RxJava 的依赖库。在 `build.gradle` 中添加以下代码: ``` implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'io.reactivex.rxjava2:rxjava:2.2.19' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' ``` 接下来,定义 Retrofit 接口: ```java public interface ApiService { @POST("path/to/post") @FormUrlEncoded Observable<ResponseBody> postRequest(@Field("param1") String param1, @Field("param2") String param2); } ``` 这里使用了 `Observable<ResponseBody>` 作为返回值,表示请求结果以响应体的形式返回。`@FormUrlEncoded` 注解表示请求参数以表单形式提交。 然后,创建 Retrofit 实例: ```java Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://example.com/") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); ApiService apiService = retrofit.create(ApiService.class); ``` 在请求使用 RxJava 的 `Observable` 对象作为被观察者,通过 `subscribeOn()` 指定请求在哪个线程执行,通过 `observeOn()` 指定结果在哪个线程回调。 ```java Observable<ResponseBody> observable = apiService.postRequest("value1", "value2"); observable.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<ResponseBody>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(ResponseBody responseBody) { // 请求成功,处理响应结果 } @Override public void onError(Throwable e) { // 请求失败,处理错误信息 } @Override public void onComplete() { } }); ``` 这里使用了 `Schedulers.io()` 来指定请求在 IO 线程执行,使用了 `AndroidSchedulers.mainThread()` 来指定结果在主线程回调。 最后,记得在代码中添加网络权限: ```xml <uses-permission android:name="android.permission.INTERNET" /> ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值