Retrofit

作者: Dapengyou | 来源:发表于2019-07-31 11:17 被阅读0次
    Retrofit源码分析.png

    根据这张思维导图,我们开始这篇文章的学习

    Retrofit到底是什么

    Retrofit主要是对Android网络请求的框架的封装,它遵循Restful设计风格,底层基于OkHttp。

    换句说,网络请求的工作本质上是OkHttp完成,而Retrofit仅负责网络请求接口的封装。

    主要是使用Retrofit接口封装请求参数、header头部、Url信息等,然后交给OkHttp完成后续的网络请求,当服务端返回数据时,OkHttp又将返回的原始数据交给Retrofit,Retrofit再根据需求解析数据

    简单明了的讲,Retrofit主要是对信息的封装

    Retrofit的使用步骤

    • 创建描述网络请求的接口
    • 创建Retrofit实例
    • 创建网络请求接口实例 并 配置网络请求参数
    • 发送网络请求
    • 处理服务器返回的数据

    接口的定义

     public interface GitHub {
        @GET("/repos/{owner}/{repo}/contributors")
        Call<List<Contributor>> contributors(
            @Path("owner") String owner,
            @Path("repo") String repo);
      }
    

    这里举的例子使用的网络请求方法是:@GET,使用的网络请求参数是:@Path

    其他注解

    网络请求方法:

    1. @GET、(常用)
    2. @POST、(常用)
    3. @PUT、
    4. @DELETE、
    5. @HEAD

    网络请求标记:

    1. @FormUrlEncoded、
    2. @Multipart、
    3. @Streaming

    网络请求参数:

    1. @Header &、
    2. @Headers、
    3. @Body、
    4. @Field 、
    5. @FieldMap、
    6. @Part 、
    7. @PartMap、
    8. @Query、
    9. @QueryMap、
    10. @Path、
    11. @Url

    https://square.github.io/retrofit/
    这里有解释上面这些注解都是怎么用的

    网络请求的代码

        //创建Retrofit实例
       Retrofit retrofit = new Retrofit.Builder()//获取到一个平台和builder对象
                    .baseUrl("xxxxxx")//xxxxxx 代表 网络请求的公共Url地址
                    .addConverterFactory(GsonConverterFactory.create())//设置数据解析器
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//支持RXJava
                    .build();
    
            //这里采用的是Java的动态代理模式,创建接口对象
            GitHub github = retrofit.create(GitHub.class);//这里 GitHub.class  是你自己建的接口
    
    
            //对 发送请求 进行封装,配置网络请求参数
            //Contributor 是你自己建的Bean,用于解析返回的数据,contributors 方法是你在接口中自己定义的方法,传入适当的参数
            Call<List<Contributor>> call = github.contributors(参数1,参数2);
    
    
            //采用异步请求
            call.enqueue(new Callback<List<Contributor>>() {
                public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) {
                    //请求成功,处理返回的数据结果
                }
    
                public void onFailure(Call<List<Contributor>> call, Throwable t) {
                    //请求失败,处理失败后的逻辑
                }
            });
            //采用同步请求
            Response<Contributor> response = call.execute();
    

    上面是Retrofit的实现步骤,并且在代码中配备了清楚的注释

    由于是从github上下的Retrofit的源码分析的,所以可能跟前辈们出的分析文章有些许的差异,但是大体上都是差不多的,这里用的版本是 :com.squareup.retrofit2:retrofit:2.5.0

    源码解析内容:

    • 解析网络请求接口的注解 配置网络请求参数
    • 动态代理 生成 网络请求对象
    • 网络请求适配器 将 网络请求对象 进行平台适配
    • 网络请求执行器 发送网络请求
    • 数据转换器 解析服务器返回的数据
    • 回调执行器 切换线程
    • 主线程处理返回结果

    看完Retrofit的使用,该来看重头戏了,Retrofit的源码分析

    创建Retrofit实例

    我们来看Retrofit实例是怎么创建的,先来看源码的追踪过程:

    //配置网络请求配置对象的,,配置对象:会对网络请求接口中的方法和注解进行解析,解析之后的对象会放在ConcurrentHashMap里面,
      // 作用是用于存储网络请求相关的一些配置,即跟网络请求相关的配置都存储在这个hashMap中,包括网络请求的一些方法,数据转换器,网络请求适配器,网络请求工厂和URL地址等
      private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
    
      //callFactory  是网络请求器的工厂,用于去生产Call请求对象,call请求就是网络请求器,无论是同步还是异步请求都是通过call调用的,并且可以看到默认的请求方式是OkHttp
      final okhttp3.Call.Factory callFactory;
      //网络请求的URL 地址,使用的 HttpUrl 类型
      final HttpUrl baseUrl;
      //数据转化器工厂的集合,作用是用于放置数据转换器工厂,而数据转换器工厂就是用于生产数据转化器 Converter 的,
      // 这里最使用的就是GsonConverterFactory ,服务器返回json 类型的数据,通过Gson解析器进行解析,并在主线程中去显示
      final List<Converter.Factory> converterFactories;
      //网络请求适配的工厂集合,作用是用于放置网络请求适配器的工厂,而网络请求适配的工厂就是用于生产网络请求适配器的
      final List<CallAdapter.Factory> callAdapterFactories;
      //回调方法执行器,主要是用于  主线程切换到子线程,子线程切换到主线程 
      final @Nullable Executor callbackExecutor;
      //标志位,判断是否提前对接口中的注解进行转换的标志位
      final boolean validateEagerly;
    

    以上就是Retrofit中的成员变量,我在上面都进行了相应的注释

     private static final Platform PLATFORM = findPlatform();
    
      static Platform get() {
        return PLATFORM;
      }
    
     /**
       * 获取对应的平台,判断是java还是android
       *
       * @return
       */
      private static Platform findPlatform() {
        try {
          //通过反射装载android.os.Build类,获取SDK的版本信息
          Class.forName("android.os.Build");
          if (Build.VERSION.SDK_INT != 0) {
            return new Android();
          }
        } catch (ClassNotFoundException ignored) {
        }
        try {
          Class.forName("java.util.Optional");
          return new Java8();
        } catch (ClassNotFoundException ignored) {
        }
        return new Platform();
      }
    
    
     static class Android extends Platform {
        @IgnoreJRERequirement // Guarded by API check.
        @Override boolean isDefaultMethod(Method method) {
          if (Build.VERSION.SDK_INT < 24) {
            return false;
          }
          return method.isDefault();
        }
    
        //创建了一个名为MainThreadExecutor的对象
        @Override public Executor defaultCallbackExecutor() {
          return new MainThreadExecutor();
        }
    
        //使用默认CallAdapter工厂生成一个执行器
        @Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
            @Nullable Executor callbackExecutor) {
          if (callbackExecutor == null) throw new AssertionError();
          DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
          return Build.VERSION.SDK_INT >= 24
            ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
            : singletonList(executorFactory);
        }
    
        @Override int defaultCallAdapterFactoriesSize() {
          return Build.VERSION.SDK_INT >= 24 ? 2 : 1;
        }
    
        @Override List<? extends Converter.Factory> defaultConverterFactories() {
          return Build.VERSION.SDK_INT >= 24
              ? singletonList(OptionalConverterFactory.INSTANCE)
              : Collections.<Converter.Factory>emptyList();
        }
    
        @Override int defaultConverterFactoriesSize() {
          return Build.VERSION.SDK_INT >= 24 ? 1 : 0;
        }
    
        //MainThreadExecutor行线程切换的执行器
        static class MainThreadExecutor implements Executor {
          private final Handler handler = new Handler(Looper.getMainLooper());
    
          //Retrofit获取主线程的handler,通过post将子线程切换至主线程
          @Override public void execute(Runnable r) {
            handler.post(r);
          }
        }
      }
    
      public Builder baseUrl(String baseUrl) {
          checkNotNull(baseUrl, "baseUrl == null");
          //将baseUrl转换为Okhttp中的HttpUrl
          return baseUrl(HttpUrl.get(baseUrl));
        }
    

    创建网络接口实例

    Retrofit内部会通过动态代理模式将接口和注解转换成HTTP请求

    动态代理模式,动态的去生成网络请求接口代理类,交给InvocationHandler代理类处理

    1. 根据返回值的类型和方法以及方法的注解从Retrofit网络请求适配器工厂以及内容转换器工厂分别获取到网络请求适配器和数据转换器
    2. 根据方法的标注对ServiceMethod的域进行赋值和成员变量赋值
    3. 为每个方法的参数的标注进行解析,获得一个 ParameterHandler<?> 对象,此对象保存了一个

    Retrofit创建的步骤

    1. 动态创建网络请求的接口的实例,在接口中定义网络请求的参数和方法,通过动态代理来拦截接口中定义好的注解,参数和方法
    2. 创建ServiceMethod对象,通过建造这模式和单例模式
    3. 对ServiceMethod对象进行网络请求参数配置,通过解析网络请求接口方法的参数的返回值、注解类型,获取url地址、线程切换的执行器、数据转换器、网络请求适配器
    4. 对ServiceMethod对象加入线程切换的操作,便于接收到数据后完成子线程到主线程的切换,然后交给主线程进行最后的数据处理
    5. 最终创建并返回一个OkHttpCall类型的网络请求对象,有了OkHttpCall对象和Request对象就可以进行网络的请求了
    1. 对网络请求接口的方法中的每个参数利用对应ParameterHandler进行解析,根据ServiceMethod对象创建一个OkHttp所使用的Request对象
    2. 使用OkHttp的Request结合OkHttpCall对象发送网络请求
    3. 对返回的数据使用之前设置的数据转换器(GsonConverterFactory)解析服务器返回的数据,得到一个Response对象
    4. 进行线程切换从而在主线程处理返回的数据结果

    Retrofit优缺点

    • 性能最好,速度最快
    • 高度封装导致扩展性差
    • 简洁易用,代码简化
    • 解耦彻底,职责细分
    • 易与其他框架联用(Rxjava)

    相关文章

      网友评论

        本文标题:Retrofit

        本文链接:https://www.haomeiwen.com/subject/carvaqtx.html