Retrofit 流程解析

Retrofit

retrofit是什么

  • 一个 RestFul 的 http 网络请求框架 (是对Okhttp的封装)
  • 网络请求的工作本质上是 OkHttp 完成,而 Retrofit 仅负责 网络请求接口的封装

retrofit 为什么存在

  • 为了优化okhttp 请求框架的使用

    • 在okhttp 相关部分讲过 okhttp 的使用

      • 其存在如下几个问题
        1. 每一个请求须手动创建request,并获取call ,
        2. 没有自动线程切换
        3. 得到的response 需手动解析
    • 而在retrofit 中

      1. 开发人员不用考虑okhttp相关的request ,call 创建获取,

        ​ Retrofit将 Http请求 抽象成 Java接口

        ​ 只需要通过注解配置好网络请求的url 和参数,由retrofit 以动态代理的形式通过CallAdapter来生 成retrofit 可用的Call 对象(此时的Call调用enqueue 又会在这里生成okhttp的call ,最终调用的还是okhttp的Call对象的enqueue的方法)

      2. 得到的response 也可以通过添加的ConverterFactory转换成对应的实体类无需手动解析

Retrofit 作用

  1. 为网络请求提供Call 对象(优化从构建request到得到Call对象的过程),并转换为retrofit可用的Call 对象
  2. 通过添加的ConvertFactory 对okhttp 请求返回的resposne 进行解析
  3. 内部完成了线程切换 通过handler 调用了 hander.post(runnable) 方法

Retrofit 使用过程 - 表层

  • 可以分为以下几步

    1. 构建Retrofit对象

      • Retrofit retrofit = new Retrofit.Builder().
                        baseUrl("https://www.test.cn/").
                        addConverterFactory(GsonConverterFactory.create()).
                        addCallAdapterFactory(RxJavaCallAdapterFactory.create()).
                        build();
        
      • 上面通过Builder.build()构建了retrofit 对象并设置其属性,下面看Builder内部分代码和build方法

      • //网络工厂 即okhttpclient 可知内部网络请求还是okhttp执行的
        private okhttp3.Call.Factory callFactory;
        //网络请求baseurl
        private HttpUrl baseUrl;
        //数据类型转换工厂集合
        private List<Converter.Factory> converterFactories = new ArrayList<>();
        //适配器工厂集合
        private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
        //callbackExecutor 也就是在这里执行的 线程切换 将子线程转换到主线程
        private Executor callbackExecutor;
        
        public Retrofit build() {
              // 检查baseurl 是否为空 为空抛出异常
              if (baseUrl == null) {
                throw new IllegalStateException("Base URL required.");
              }
        	 //检查CallFactory 是否为空 为空则默认添加一个OkhttpClient
              okhttp3.Call.Factory callFactory = this.callFactory;
              if (callFactory == null) {
                callFactory = new OkHttpClient();
              }
        	  // 创建回调执行器 用来进行线程切换
              Executor callbackExecutor = this.callbackExecutor;
              if (callbackExecutor == null) {
                callbackExecutor = platform.defaultCallbackExecutor();
              }
        
              // 创建适配器的集合,并添加默认的Call适配器。这里即使不设置CallAdapter 也会添加一个默认的
              // 这就是为什么我们主动添加CallAdapter 仍能转换为Call的原因
              List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
              adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
        
              // 创建转换器集合
              List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
        	// 创建retrofit 
              return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
                  callbackExecutor, validateEagerly);
            }
        
      • 可知在构建Retrofit的时 配置了retrofit 的各项属性 为空的则添加默认值

    2. 创建用于描述网络请求的接口

      • public interface MyService {
            @GET("users/{user}/repos")
            Call<String> getParams();
        }
        
    3. 创建网络请求接口实例

      • MyService service = retrofit.create(MyService.class);
        
    4. 获取Call对象调用网络请求

      • service.getParams().enqueue(new Callback<String>() {
                    @Override
                    public void onResponse(Call<String> call, Response<String> response) {
                        
                    }
        
                    @Override
                    public void onFailure(Call<String> call, Throwable t) {
        
                    }
                });
        
      • 此时线程已经切换回了主线程 至于如何切换的后面会提到

Retrofit 详细流程

  • 上面我们了解retrofit的作用
      1. 为网络请求提供Call 对象(开发人员无需手动构建request 和 call )
      1. 将网络请求的结果response解析进行类型转换
      1. 进行线程切换

retrofit 怎么封装的Call对象

  • 说到这里 首先从上面的流程中我们知道到得到Call对象我们经历了以下几步

      1. 构建retrofit
      2. 创建用于请求的接口
      3. 通过retrofit.create方法创建网络请求接口的代理类
      4. 通过代理类获取call 对象
    • 其实前面两步没啥可说的 就是创建了一个Retrofit 创建了一个接口,第三步还有点能说的,重点在retrofit.create() 方法内 下面我们看下create 方法内做了什么

      • public <T> T create(final Class<T> service) {
        	// 调用 Proxy.newProxyInstance 得到 MyService的代理对象
            return (T) Proxy.newProxyInstance(
                service.getClassLoader(), 
                new Class<?>[] { service },
                //这个参数是一个实现了InvocationHandler接口的中介类用做“调用处理器”,当我们调用代理类对象的方法时,这个“调用”会转送到invoke方法中,
                //这里直接用用了匿名类的写法
                new InvocationHandler() {
                  private final Platform platform = Platform.get();
        		 // 重写了invoke方法,当代理对象调用其内部方法时 实际上是通过改中介类的invoke方法调用的
                  @Override public Object invoke(Object proxy, Method method, Object... args)
                      throws Throwable {
                    if (method.getDeclaringClass() == Object.class) {
                      return method.invoke(this, args);
                    }
                    if (platform.isDefaultMethod(method)) {
                      return platform.invokeDefaultMethod(method, service, proxy, args);
                    }
                     //加载ServiceMethod
                    ServiceMethod serviceMethod = loadServiceMethod(method);
                     // 通过serviceMethod创建一个OkhttpCall 这个OkhttpCall 是retrofit自己封装的,不是Okhttp里面的Call
                    OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
                     // 通过Adapter.adapt 返回一个 Call 对象
                    return serviceMethod.callAdapter.adapt(okHttpCall);
                  }
                });
        
        • ServiceMethod是什么
          • (官翻)将接口方法的调用调整为HTTP调用的类。
          • 其内部维护一个retrofit 和 method 并存储了该
        • 我们看下loadServiceMethod内做了什么
        ServiceMethod loadServiceMethod(Method method) {
            ServiceMethod result;
            synchronized (serviceMethodCache) {
             // 从缓存中获取method对应的ServiceMethod对象 若没有则创建一个并放到缓存里
              result = serviceMethodCache.get(method);
              if (result == null) {
                result = new ServiceMethod.Builder(this, method).build();
                serviceMethodCache.put(method, result);
              }
            }
            return result;
          }
        
        • loadServiceMethod方法

          • 从缓存中获取method对应的ServiceMethod对象 若没有则创建一个并放到缓存里

          • 通过Builder 传递一个retrofit 和method 构建了一个ServiceMethod

            • 下面我们看这里做了什么

            • ServiceMethod.Builder(retrofit, method).build()
              public Builder(Retrofit retrofit, Method method) {
                    this.retrofit = retrofit;
                    this.method = method;
                    this.methodAnnotations = method.getAnnotations();
                    this.parameterTypes = method.getGenericParameterTypes();
                    this.parameterAnnotationsArray = 		method.getParameterAnnotations();
                  }
              public ServiceMethod build() {
              	 //1. 根据方法的返回类型和注解,从retrofit实例中获取CallAapter对象。 就是获取构建retrofit时设置的适配器 
                    callAdapter = createCallAdapter();
                    responseType = callAdapter.responseType();
                    if (responseType == Response.class || responseType == okhttp3.Response.class) {
                      throw methodError("'"
                          + Utils.getRawType(responseType).getName()
                          + "' is not a valid response body type. Did you mean ResponseBody?");
                    }
                      //2. 获取response的转换器就是获取构建retrofit 时设置的转换器
                    responseConverter = createResponseConverter();
              	 // 遍历注解
                    for (Annotation annotation : methodAnnotations) {
                       // 解析注解
                      parseMethodAnnotation(annotation);
                    }
              	//`````
                    int parameterCount = parameterAnnotationsArray.length;
                    parameterHandlers = new ParameterHandler<?>[parameterCount];
                    for (int p = 0; p < parameterCount; p++) {
                      Type parameterType = parameterTypes[p];
                      if (Utils.hasUnresolvableType(parameterType)) {
                        throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
                            parameterType);
                      }
              
                      Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
                      if (parameterAnnotations == null) {
                        throw parameterError(p, "No Retrofit annotation found.");
                      }
              
                      parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
                    }
              	//````返回 ServiceMethod
                    return new ServiceMethod<>(this);
                  }
              
              • 代码可知
                • ServiceMethod在构建时就已将传递进去的method 的注解,各项信息解析并保存在了当前ServiceMethod对象里
                • 获取了根据类型和注解获取了CallAdapter
                • 获取了类型转换器
        • 继续向下执行

          • 通过methodService创建了okhttpCall对象
          • 通过CallAdapter.adapt 获取可用于网络请求的Call
      • 总结

        • 由上可知 从得到可用于网络请求的Call 经历如下步骤
        1. 调用retrofit.create 方法,

        2. 通过动态代理获取代理类对象

        3. 通过代理类对象调用其内部的方法时其实调用中介类的invoke 方法得到一个Call对象,invoke方法内部执行了如下步骤

        4. 构建一个ServieMethod 对象

        5. 通过 ServieMethod 创建一个OkhttpCall

        6. 通过CallAdapter.adapt 的到一个代理类对象方法所对应的Call对象(这里还是Retrofit的自己封装的Call,在执行该Call时才会转换为Okhttp的Call)


        • 这里的call 仅是retrofit 可用的call 真正执行网络请求之前还要转换成okhttp可用的Call 才行

Retrofit 如何进行的网络请求

  • 上面我们知道retrofit 如何获取的Call对象

  • 当我们获取到Call对象之后 即可进行网络请求

    • call.enqueue 调用 enqueue 方法即可

    • 此时先执行到ExecutorCallbackCall中的enqueue 我们看enqueue 内部

      •  @Override public void enqueue(final Callback<T> callback) {
              if (callback == null) throw new NullPointerException("callback == null");
        
              delegate.enqueue(new Callback<T>() {
                @Override public void onResponse(Call<T> call, final Response<T> response) {          
                   //5 注意此处 之这里就是完成 子线程转主线程
                  callbackExecutor.execute(new Runnable() {
                    @Override public void run() {
                      if (delegate.isCanceled()) {
                        // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                        callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                      } else {
                        callback.onResponse(ExecutorCallbackCall.this, response);
                      }
                    }
                  });
                }
        
                @Override public void onFailure(Call<T> call, final Throwable t) {
                  callbackExecutor.execute(new Runnable() {
                    @Override public void run() {
                      callback.onFailure(ExecutorCallbackCall.this, t);
                    }
                  });
                }
              });
            }
        
      • 我们可以看到 内部通过delegate又调用了enqueue

        • delegate 是Call 对象

        • 这次是到了okhttpcall中的enqueue

        •   @Override public void enqueue(final Callback<T> callback) {
              if (callback == null) throw new NullPointerException("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 {
                    // 1 创建真正可用于网络请求的Call Okhttp的Call对象
                    call = rawCall = createRawCall();
                  } catch (Throwable t) {
                    failure = creationFailure = t;
                  }
                }
              }
          
              if (failure != null) {
                callback.onFailure(this, failure);
                return;
              }
          
              if (canceled) {
                call.cancel();
              }
          	// 2 通过Okhttp 的Call 对象调用enqueue 执行异步网络请求
              call.enqueue(new okhttp3.Callback() {
                @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
                    throws IOException {
                  Response<T> response;
                  try {
                     // 3 解析response
                    response = parseResponse(rawResponse);
                  } catch (Throwable e) {
                    callFailure(e);
                    return;
                  }
                   // 4 通过回调将结果回传给ExecutorCallbackCall
                  callSuccess(response);
                }
          
                @Override public void onFailure(okhttp3.Call call, IOException e) {
                  try {
                    callback.onFailure(OkHttpCall.this, e);
                  } catch (Throwable t) {
                    t.printStackTrace();
                  }
                }
          
                private void callFailure(Throwable e) {
                  try {
                    callback.onFailure(OkHttpCall.this, e);
                  } catch (Throwable t) {
                    t.printStackTrace();
                  }
                }
          
                private void callSuccess(Response<T> response) {
                  try {
                    callback.onResponse(OkHttpCall.this, response);
                  } catch (Throwable t) {
                    t.printStackTrace();
                  }
                }
              });
            }
          
  • 总结

    • 由上面代码可知 调用enqueue 执行如下过程
      • 1 首先调用enqueue 方法生成Okhttp 的Call对象
      • 2 call对象执行网络请求
      • 3 解析respnse
      • 4 通过回调 讲结果传递出去
      • 5 ExecutorCallbackCall 中将回调结果进行线程切换
        • 因为是回调 执行结束才能拿到值 所以代码顺序 5 在1,2,3,4 之前

Retrofit 如何进行线程切换

  • 在上面步骤中我们知道了在ExecutorCallbackCall.enqueuecallBack中,retrofit 通过callbackExecutor.executeresponse转换到了主线程

  • 那他是如何转换的呢

    • 首先这里的callbackExecutor 是在retrofit 的构建中赋值的

      •  public Retrofit build() {
              Executor callbackExecutor = this.callbackExecutor;
              if (callbackExecutor == null) {
                callbackExecutor = platform.defaultCallbackExecutor();
              }
              return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
                  callbackExecutor, validateEagerly);
            }
        
      • 可以看到 通过platform.defaultCallbackExecutor();

        • platform 是一个平台 支持Android 和 java 在这里我们是安卓平台

          • platform 在builder里面创建

            •     public Builder() {
                    this(Platform.get());
                  }
                  private static final Platform PLATFORM = findPlatform();
              
                static Platform get() {
                  return PLATFORM;
                }
              
                private static Platform findPlatform() {
                  try {
                    Class.forName("android.os.Build");
                    if (Build.VERSION.SDK_INT != 0) {
                      return new Android();
                    }
                  } catch (ClassNotFoundException ignored) {
                  }
                  return new Platform();
                }
              
            • 这里返回的是安卓

        • defaultCallbackExecutor 也就是Andorid.defaultCallbackExecutor

          • static class Android extends Platform {
              	// 生成默认的 Executor
                @Override public Executor defaultCallbackExecutor() {
                return new MainThreadExecutor();
              }
            	// 生成默认的 CallAdapterFactory
              @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
                return new ExecutorCallAdapterFactory(callbackExecutor);
              }
            
              static class MainThreadExecutor implements Executor {
                 // 线程切换通过handler
                private final Handler handler = new Handler(Looper.getMainLooper());
            
                @Override public void execute(Runnable r) {
                  handler.post(r);
                }
              }
            }
            
            • 由上代码可知
            • 生成默认的 Executor 也就是 MainThreadExecutor
              • MainThreadExecutor内部维护了一个Handler
              • execute方法内部通过Handler.post 完成了线程切换
              • 所以callbackExecutor.execute 即 MainThreadExecutor.execute
                • 内部通过handler 完成线程切换
            • 生成默认的 CallAdapterFactory

总结

  • retrofit 实质上是对okhttp的封装,隐藏生成request 和call 的实现,完成了线程切换,使用起来更方便,实际上网络请求还是通过okhttp完成的
  • 其内部使用了很多设计模式
    • 门面模式 比如retrofit .create 只需要传递进去接口class 即可 无需关心内部实现
    • 动态代理模式 获取接口文件的代理对象
    • builder 模式 创建retorfit对象
    • 适配器模式,通过CallAdapter.adapt 返回Call对象
  • 流程就不画了描述一下吧
    1. 创建retrofit对象
    2. 创建用于描述网络请求的接口文件
    3. 调用retrofit.create 通过动态代理获取接口文件的代理类proxy
    4. proxy调用内部方法 通过调用中介类的invoke方法获取Call对象
      1. 构建MethodService对象
      2. 通过MethodService创建OkHttpCall
      3. 通过CallAdapter.adapt 得到Call对象
    5. 通过Call对象调用enqueue方法传进去CallBack 用于处理结果
      1. 将OkhttpCall 转换成 okhttp的call对象
      2. call 执行网络请求 获取response
      3. 解析response 调用类型转换器转换
      4. 通过回调返回结果
      5. callbackExecuter.execute 进行线程切换
    6. 得到结果进行操作 至此流程结束
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值