Retrofit

简介

Retrofit是一个Restful设计风格的Http网络请求框架,基于OkHttp

功能

  • 基于OkHttp、遵循restful api设计风格
  • 通过注解配置网络请求参数
  • 支持同步、异步的网络请求
  • 支持多种数据的解析和序列化格式(Gson、Json、XML、Protobuf)
  • 提供了对RxJava的支持

优点

功能强大、简洁易用、可扩展性好

应用场景

任何网络请求的场景都应该优先选择,特别是后台API遵循restful API设计风格或项目中使用到RxJava时

小结

  • 准确来说,Retrofit是一个RESTful的Http网络请求框架的封装

  • 原因:网络请求的工作本质上是Okhttp完成,而Retrofit仅负责啊网络请求接口的封装

  • 在这里插入图片描述

  • App应用程序通过Retrofit请求网络,实际上是使用Retrofit接口层封装请求参数、Header、Url等信息,之后由OkHttp完成后续的请求操作

  • 在服务端返回数据之后,Okhttp将原始的结果交给Retrofit,Retrofit根据用户的需求对结果进行解析

使用

  • 引入Retrofit库的依赖
  • 创建接收服务器返回数据的类
  • 创建用于描述网络请求的接口 :Retrofit将http请求抽象成java接口。用动态代理动态将该接口的注解翻译成一个Http请求,最后再执行Http请求
  • 创建Retrofit实例
  • 创建网络请求接口实例并配置网络请求参数
  • 发送网络请求(异步/同步)

封装了数据转换、线程切换的操作

  • 处理服务器返回的数据

注解类型

在这里插入图片描述

注解说明

在这里插入图片描述

Retrofit把网络请求的Url分成了两部分设置:

// 第1部分:在网络请求接口的注解设置
 @GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car")
Call<Translation>  getCall();

// 第2部分:在创建Retrofit实例时通过.baseUrl()设置
Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://fanyi.youdao.com/") //设置网络请求的Url地址
                .addConverterFactory(GsonConverterFactory.create()) //设置数据解析器
                .build();

// 从上面看出:一个请求的URL可以通过 替换块 和 请求方法的参数 来进行动态的URL更新。
// 替换块是由 被{}包裹起来的字符串构成
// 即:Retrofit支持动态改变网络请求根目录

网络请求的完整Url : 在创建Retrofit实例时通过.baseUrl()设置 + 网络请求接口的注解设置

标记

在这里插入图片描述

@FormUrlEncoded

  • 作用:表示发送form-encoded的数据

每个键值对需要用@Filed来注解键名,随后的对象需要提供值

@Multipart

  • 作用:表示发送form-encoded数据(适用于有文件上传的场景)

每个键值对需要用@Part来注解键名,随后的对象需要提供值

具体使用如下:

public interface GetRequest_Interface {
        /**
         *表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
         * <code>Field("username")</code> 表示将后面的 <code>String name</code> 中name的取值作为 username 的值
         */
        @POST("/form")
        @FormUrlEncoded
        Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);
         
        /**
         * {@link Part} 后面支持三种类型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意类型
         * 除 {@link okhttp3.MultipartBody.Part} 以外,其它类型都必须带上表单字段({@link okhttp3.MultipartBody.Part} 中已经包含了表单字段的信息),
         */
        @POST("/form")
        @Multipart
        Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file);

}

// 具体使用
       GetRequest_Interface service = retrofit.create(GetRequest_Interface.class);
        // @FormUrlEncoded 
        Call<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24);
        
        //  @Multipart
        RequestBody name = RequestBody.create(textType, "Carson");
        RequestBody age = RequestBody.create(textType, "24");

        MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file);
        Call<ResponseBody> call3 = service.testFileUpload1(name, age, filePart);

网络请求参数

在这里插入图片描述

详细说明

a. @Header、@Headers

  • 作用:添加请求头/添加不固定的请求头
  • 具体使用如下:
// @Header
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)

// @Headers
@Headers("Authorization: authorization")
@GET("user")
Call<User> getUser()

// 以上的效果是一致的。
// 区别在于使用场景和使用方式
// 1. 使用场景:@Header用于添加不固定的请求头,@Headers用于添加固定的请求头
// 2. 使用方式:@Header作用于方法的参数;@Headers作用于方法

b. @Body

  • 作用:以Post方式传递自定义数据类型给服务器
  • 特别注意:如果提交的是一个Map,那么作用相当于@Field

Map经过FormBody.Builder类处理成符合OkHttp格式的表单,如:

FormBody.Builder builder = new FormBody.Builder();
builder.add("key","value");

c. @Filed、@FiledMap

  • 作用:发送Post请求时提交请求的表单字段
  • 具体使用:与@FormUrlEncoded注解配合使用
public interface GetRequest_Interface {
        /**
         *表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
         * <code>Field("username")</code> 表示将后面的 <code>String name</code> 中name的取值作为 username 的值
         */
        @POST("/form")
        @FormUrlEncoded
        Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);

/**
         * Map的key作为表单的键
         */
        @POST("/form")
        @FormUrlEncoded
        Call<ResponseBody> testFormUrlEncoded2(@FieldMap Map<String, Object> map);

}

// 具体使用
         // @Field
        Call<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24);

        // @FieldMap
        // 实现的效果与上面相同,但要传入Map
        Map<String, Object> map = new HashMap<>();
        map.put("username", "Carson");
        map.put("age", 24);
        Call<ResponseBody> call2 = service.testFormUrlEncoded2(map);

d. @Query、@QueryMap

  • 作用
    用于@GET方法的查询参数(Query = Url中’?'后面的key-value)

如:url = http://www.println.net/?cate=android 其中,Query = cate

   @GET("/")    
   Call<String> cate(@Query("cate") String cate);
}

// 其使用方式同 @Field与@FieldMap,这里不作过多描述

f. @Path

  • 作用
    URL地址的缺省值

  • 具体使用

public interface GetRequest_Interface {

        @GET("users/{user}/repos")
        Call<ResponseBody>  getBlog(@Path("user") String user );
        // 访问的API是:https://api.github.com/users/{user}/repos
        // 在发起请求时, {user} 会被替换为方法的第一个参数 user(被@Path注解作用)
    }

g. @Url

  • 作用
    直接传入一个请求的Url变量用于URL设置

  • 具体使用

public interface GetRequest_Interface {

        @GET
        Call<ResponseBody> testUrlAndQuery(@Url String url, @Query("showAll") boolean showAll);
       // 当有URL注解时,@GET传入的URL就可以省略
       // 当GET、POST...HTTP等方法中没有设置Url时,则必须使用 {@link Url}提供

}

原理

网络请求的过程

在这里插入图片描述

Retrofit与普通网络请求的比较

在这里插入图片描述

具体过程如下:

1.通过解析 网络请求接口的注解 配置网络请求参数
2.通过 动态代理 生成网络请求对象
3.通过 网络请求适配器 将网络请求对象进行平台适配
4.通过 网络请求执行器 发送网络请求
5.通过 数据转换器 解析服务器返回的数据
6.通过回调执行器切换线程(子线程 -> 主线程)
7.用户在主线程处理返回结果
在这里插入图片描述

Retrofit类

<-- Retrofit类 -->
 public final class Retrofit {
  
  private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
  // 网络请求配置对象(对网络请求接口中方法注解进行解析后得到的对象)
  // 作用:存储网络请求相关的配置,如网络请求的方法、数据转换器、网络请求适配器、网络请求工厂、基地址等
  
  private final HttpUrl baseUrl;
  // 网络请求的url地址

  private final okhttp3.Call.Factory callFactory;
  // 网络请求器的工厂
  // 作用:生产网络请求器(Call)
  // Retrofit是默认使用okhttp
  
   private final List<CallAdapter.Factory> adapterFactories;
  // 网络请求适配器工厂的集合
  // 作用:放置网络请求适配器工厂
  // 网络请求适配器工厂作用:生产网络请求适配器(CallAdapter)
  // 下面会详细说明


  private final List<Converter.Factory> converterFactories;
  // 数据转换器工厂的集合
  // 作用:放置数据转换器工厂
  // 数据转换器工厂作用:生产数据转换器(converter)

  private final Executor callbackExecutor;
  // 回调方法执行器

private final boolean validateEagerly; 
// 标志位
// 作用:是否提前对业务接口中的注解进行验证转换的标志位


<-- Retrofit类的构造函数 -->
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,  
      List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,  
      Executor callbackExecutor, boolean validateEagerly) {  
    this.callFactory = callFactory;  
    this.baseUrl = baseUrl;  
    this.converterFactories = unmodifiableList(converterFactories); 
    this.adapterFactories = unmodifiableList(adapterFactories);   
    // unmodifiableList(list)近似于UnmodifiableList<E>(list)
    // 作用:创建的新对象能够对list数据进行访问,但不可通过该对象对list集合中的元素进行修改
    this.callbackExecutor = callbackExecutor;  
    this.validateEagerly = validateEagerly;  
  ...
  // 仅贴出关键代码
}

成功建立一个Retrofit对象的标准:配置好Retrofit类里的成员变量

  • serviceMethod : 包含所有网络请求信息的对象
  • baseUrl : 网络请求的url地址
  • callFactory : 网络请求工厂
  • adapterFactories : 网络请求适配器工厂的集合
  • converterFactories : 数据转换工厂的集合
  • callbackExecutor : 回调方法执行器

CallAdapter

  • 定义 : 网络请求执行器(Call)的适配器

1.Call在Retrofit里默认是OkHttpCall
2.在Retrofit中提供了四种CallAdapterFactory:ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory

  • 作用:将默认的网络请求执行器(OkHttpCall)转换成适合被不同平台来调用的网络请求执行器形式

1.例如:一开始Retrofit只打算利用OkHttpCall通过ExecutorCallbackCall切换线程,但是后来发现使用RxJava更加方便(不需要Handler切换线程)。想要实现Rxjava的方式,就要使用RxJavaCallAdapterFactoryCallAdapter将OkHttpCall转换成RxJava(Scheduler);
2.Retrofit还支持java8、Guava平台

  • 好处 : 用最小的代价兼容更多平台,即能适配更多的使用场景

Builder类

<-- Builder类-->
public static final class Builder {
    private Platform platform;
    private okhttp3.Call.Factory callFactory;
    private HttpUrl baseUrl;
    private List<Converter.Factory> converterFactories = new ArrayList<>();
    private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
    private Executor callbackExecutor;
    private boolean validateEagerly;

// 从上面可以发现, Builder类的成员变量与Retrofit类的成员变量是对应的
// 所以Retrofit类的成员变量基本上是通过Builder类进行配置
// 开始看步骤1

<-- 步骤1 -->
// Builder的构造方法(无参)
 public Builder() {
      this(Platform.get());
// 用this调用自己的有参构造方法public Builder(Platform platform) ->>步骤5(看完步骤2、3、4再看)
// 并通过调用Platform.get()传入了Platform对象
// 继续看Platform.get()方法 ->>步骤2
// 记得最后继续看步骤5的Builder有参构造方法
    }
...
}

<-- 步骤2 -->
class Platform {

  private static final Platform PLATFORM = findPlatform();
  // 将findPlatform()赋给静态变量

  static Platform get() {
    return PLATFORM;    
    // 返回静态变量PLATFORM,即findPlatform() ->>步骤3
  }

<-- 步骤3 -->
private static Platform findPlatform() {
    try {

      Class.forName("android.os.Build");
      // Class.forName(xxx.xx.xx)的作用:要求JVM查找并加载指定的类(即JVM会执行该类的静态代码段)
      if (Build.VERSION.SDK_INT != 0) {
        return new Android(); 
        // 此处表示:如果是Android平台,就创建并返回一个Android对象 ->>步骤4
      }
    } catch (ClassNotFoundException ignored) {
    }

    try {
      // 支持Java平台
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }

    try {
      // 支持iOS平台
      Class.forName("org.robovm.apple.foundation.NSObject");
      return new IOS();
    } catch (ClassNotFoundException ignored) {
    }

// 从上面看出:Retrofit2.0支持3个平台:Android平台、Java平台、IOS平台
// 最后返回一个Platform对象(指定了Android平台)给Builder的有参构造方法public Builder(Platform platform)  --> 步骤5
// 说明Builder指定了运行平台为Android
    return new Platform();
  }
...
}

<-- 步骤4 -->
// 用于接收服务器返回数据后进行线程切换在主线程显示结果

static class Android extends Platform {

    @Override
      CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {

      return new ExecutorCallAdapterFactory(callbackExecutor);
    // 创建默认的网络请求适配器工厂
    // 该默认工厂生产的 adapter 会使得Call在异步调用时在指定的 Executor 上执行回调
    // 在Retrofit中提供了四种CallAdapterFactory: ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory
    // 采用了策略模式
    
    }

    @Override 
      public Executor defaultCallbackExecutor() {
      // 返回一个默认的回调方法执行器
      // 该执行器作用:切换线程(子->>主线程),并在主线程(UI线程)中执行回调方法
      return new MainThreadExecutor();
    }

    static class MainThreadExecutor implements Executor {
   
      private final Handler handler = new Handler(Looper.getMainLooper());
      // 获取与Android 主线程绑定的Handler 

      @Override 
      public void execute(Runnable r) {
        
        
        handler.post(r);
        // 该Handler是上面获取的与Android 主线程绑定的Handler 
        // 在UI线程进行对网络请求返回数据处理等操作。
      }
    }

// 切换线程的流程:
// 1. 回调ExecutorCallAdapterFactory生成了一个ExecutorCallbackCall对象
//2. 通过调用ExecutorCallbackCall.enqueue(CallBack)从而调用MainThreadExecutor的execute()通过handler切换到主线程
  }

// 下面继续看步骤5的Builder有参构造方法
<-- 步骤5 -->
//  Builder类的构造函数2(有参)
  public  Builder(Platform platform) {

  // 接收Platform对象(Android平台)
      this.platform = platform;

// 通过传入BuiltInConverters()对象配置数据转换器工厂(converterFactories)

// converterFactories是一个存放数据转换器Converter.Factory的数组
// 配置converterFactories即配置里面的数据转换器
      converterFactories.add(new BuiltInConverters());

// BuiltInConverters是一个内置的数据转换器工厂(继承Converter.Factory类)
// new BuiltInConverters()是为了初始化数据转换器
    }

Builder类设置了默认的属性

  • 平台类型对象 : Android
  • 网络请求适配器工厂 : CallAdapterFactory

CallAdapter用于对原始Call进行再次封装,如Call到Observable

  • 数据转换器工厂 : converterFactory
  • 回调执行器 : callbackExecutor

baseUrl

<-- 步骤1 -->
public Builder baseUrl(String baseUrl) {

      // 把String类型的url参数转化为适合OKhttp的HttpUrl类型
      HttpUrl httpUrl = HttpUrl.parse(baseUrl);     

    // 最终返回带httpUrl类型参数的baseUrl()
    // 下面继续看baseUrl(httpUrl) ->> 步骤2
      return baseUrl(httpUrl);
    }


<-- 步骤2 -->
    public Builder baseUrl(HttpUrl baseUrl) {

      //把URL参数分割成几个路径碎片
      List<String> pathSegments = baseUrl.pathSegments();   

      // 检测最后一个碎片来检查URL参数是不是以"/"结尾
      // 不是就抛出异常    
      if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
      }     
      this.baseUrl = baseUrl;
      return this;
    }

baseUrl()用于配置Retrofit类的网络请求url地址。它可以将传入的String类型的url转换为Okhttp的HttpUrl类型的url

GsonConverterFactory.create()

public final class GsonConverterFactory extends Converter.Factory {

<-- 步骤1 -->
  public static GsonConverterFactory create() {
    // 创建一个Gson对象
    return create(new Gson()); ->>步骤2
  }

<-- 步骤2 -->
  public static GsonConverterFactory create(Gson gson) {
    // 创建了一个含有Gson对象实例的GsonConverterFactory
    return new GsonConverterFactory(gson); ->>步骤3
  }

  private final Gson gson;

<-- 步骤3 -->
  private GsonConverterFactory(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    this.gson = gson;
  }


所以,GsonConverterFactory.create()是创建了一个含有Gson对象实例的GsonConverterFactory,并返回给addConverterFactory

addConverterFactory()


// 将上面创建的GsonConverterFactory放入到 converterFactories数组
// 在第二步放入一个内置的数据转换器工厂BuiltInConverters()后又放入了一个GsonConverterFactory
  public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }


1.Retrofit默认使用Gson进行解析
2.若使用其他解析方式(Json、XML、Protobuf),也可以通过自定义数据解析器来实现(必须继承Converter.Factory)

异步请求OkHttpCall.enqueue()

发送请求的过程

  • 对网络请求接口的方法中的每个参数利用对应ParameterHandler进行解析,再根据ServiceMethod对象创建一个OkHttp的Request对象

  • 使用OkHttp的Request发送网络请求

  • 对返回的数据使用之前设置的数据转换器(GsonConverterFactory)解析返回的数据,最终得到一个Response对象

  • 进行线程切换从而在主线程处理返回的数据结果

若使用了RxJava,则直接回调到主线程

异步请求的过程跟同步请求类似,唯一不同的是:异步请求会将回调方法交给回调执行器在指定的线程中执行(UI线程)

总结

Retrofit使用建造者模式通过Builder类建立了一个Retrofit实例,具体创建细节:

  • 平台类型对象(plateform-Android)

  • 网络请求的url地址(baseUrl)

  • 网络请求工厂(callFactory)

默认使用OkHttpCall

  • 网络请求适配器工厂的集合(adapterFactories)

本质是配置了网络请求适配器工厂——默认是ExecutorCallAdapterFactory

  • 数据转换器工厂的集合(converterFactories)

本质是配置了数据转换器工厂

  • 回调方法执行器(callbackExecutor)

默认回调方法执行器作用是:切换线程(子线程 -> 主线程)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值