我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Retrofit网络请求和响应处理源码分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Retrofit网络请求和响应处理源码分析

本篇内容主要讲解“Retrofit网络请求和响应处理源码分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Retrofit网络请求和响应处理源码分析”吧!

网络请求

在使用 Retrofit 发起网络请求时,我们可以通过定义一个接口并使用 Retrofit 的注解来描述这个接口中的请求,Retrofit 会自动生成一个实现该接口的代理对象。当我们调用这个代理对象的方法时,Retrofit 会根据注解的描述构建一个 Request 对象,并使用 OkHttp 将这个 Request 发送出去。

在 Retrofit 中,我们可以通过 Retrofit#executeRetrofit#enqueue 方法来发送请求。这两个方法的区别在于,execute 方法会阻塞当前线程直到请求完成,而 enqueue 方法会将请求加入到 OkHttp 的请求队列中,并在请求完成时通过回调通知我们。

我们先来看一下 execute 方法的实现:

public <T> T execute(Call<T> call) throws IOException {  Utils.validateServiceInterface(call.request().tag(), call.request().url().toString());  return (T) callAdapter(call, call.request().tag()).adapt(call).execute();}

在这个方法中,首先会对接口进行校验,确保这个接口是有效的。然后我们会根据请求的 Tag 和 URL 来获取适配器callAdapter,并使用适配器来执行请求。

适配器的作用是将请求的参数适配成 OkHttp 能够识别的形式,并将 OkHttp 的响应适配成我们需要的形式。Retrofit 提供了一系列的适配器,包括 Call 适配器、RxJava 适配器、CompletableFuture 适配器等。

我们来看一下 callAdapter 方法的实现:

private CallAdapter<?, ?> callAdapter(Call<?> call, Object tag) {  Type responseType = call.request().method().equals("HEAD")      ? Void.class      : getParameterUpperBound(0, (ParameterizedType) call.request().tag());  return callAdapter(tag, responseType);}

在这个方法中,我们首先根据请求的方法来判断响应的类型,如果是 HEAD 方法,那么响应的类型就是 Void;否则我们会通过反射来获取请求的响应类型,并使用这个响应类型来获取适配器。

获取适配器的方法是 callAdapter

public <R, T> CallAdapter<R, T> callAdapter(Object tag, Type returnType) {  // ...  for (CallAdapter.Factory factory : adapterFactories) {    CallAdapter<?, ?> adapter = factory.get(returnType, annotations, this);    if (adapter != null) {      return (CallAdapter<R, T>) adapter;    }  }  // ...}

在这个方法中,我们会遍历所有的适配器工厂,尝试获取适配器。在获取适配器时,我们会将请求的响应类型、注解和 Retrofit 实例作为参数传入。每个适配器工厂都会判断这些参数是否符合自己的适配条件,如果符合,就返回一个适配器实例,否则返回 null。在遍历完所有的适配器工厂之后,如果还没有获取到适配器,那么就会抛出一个异常。

获取到适配器之后,我们就可以使用适配器来执行请求了。在适配器中,我们会将请求参数转换成 OkHttp 的 Request 对象,并将 OkHttp 的 Response 对象转换成我们需要的响应类型。具体的实现可以参考 Retrofit 提供的 CallAdapter 接口。

对于 enqueue 方法,我们可以先来看一下 enqueue 方法的实现:

public <T> void enqueue(Call<T> call, Callback<T> callback) {  Utils.validateServiceInterface(call.request().tag(), call.request().url().toString());  callAdapter(call, call.request().tag()).adapt(call).enqueue(new CallbackRunnable<>(callback));}

在这个方法中,我们首先进行接口校验,然后根据请求的 Tag 和 URL 来获取适配器,并使用适配器来执行请求。不同的是,在 enqueue 方法中,我们将一个 Callback 对象作为参数传入适配器的 enqueue 方法中,以便在请求完成后回调通知我们。

在适配器中,我们可以看到 enqueue 方法的实现:

public void enqueue(final Callback<T> callback) {  delegate.enqueue(new Callback<Response<T>>() {    @Override public void onResponse(Call<Response<T>> call, Response<Response<T>> response) {      Response<T> body;      try {        body = response.body();      } catch (Throwable t) {        if (response.code() == 204) {          body = null;        } else {          callback.onFailure(call, t);          return;        }      }      if (response.isSuccessful()) {        callback.onResponse(call, Response.success(body, response.raw()));      } else {        callback.onFailure(call, Response.error(response.errorBody(), response.raw()));      }    }    @Override public void onFailure(Call<Response<T>> call, Throwable t) {      callback.onFailure(call, t);    }  });}

在这个方法中,我们会将传入的 Callback 对象转换成一个 Callback<Response<T>> 对象,并使用这个对象来调用 OkHttp 的 enqueue 方法。在请求完成后,我们会将 OkHttp 的 Response 对象转换成 Retrofit 的 Response 对象,并根据响应码来判断请求的结果。如果响应码表示请求成功,那么我们就调用 Callback 对象的 onResponse 方法;否则就调用 Callback 对象的 onFailure 方法。

响应处理

在 Retrofit 中,我们可以通过定义一个接口并使用注解来描述我们期望的请求格式和响应格式。例如,我们可以通过 @GET 注解来描述一个 GET 请求,使用 @Query 注解来描述请求参数,使用 @Body 注解来描述请求体,使用 @Headers 注解来描述请求头等。

在执行请求时,Retrofit 会根据这些注解来自动生成一个对应的请求对象,并将请求对象转换成 OkHttp 的 Request 对象。在接收响应时,Retrofit 会将 OkHttp 的 Response 对象转换成一个对应的响应对象,并将响应对象中的数据转换成我们需要的数据类型。这些转换工作是通过 Retrofit 的转换器来完成的,Retrofit 中默认提供了两个转换器:GsonConverterFactoryJacksonConverterFactory。我们也可以自定义一个转换器来实现我们期望的数据转换。

在 Retrofit 类的构造方法中,我们可以看到 Retrofit 默认使用了 Platform.get() 方法来获取当前运行平台的默认转换器工厂,并将其添加到 converterFactories 中。然后,我们可以使用 addConverterFactory 方法来添加自定义的转换器工厂。

public Retrofit(Builder builder) {  // ...  if (builder.converterFactories == null) {    converterFactories.add(Platform.get().defaultConverterFactory());  } else {    converterFactories.addAll(builder.converterFactories);  }  // ...}public interface Platform {  // ...  Converter.Factory defaultConverterFactory();}

execute方法中,我们会调用适配器的 adapt 方法来执行请求,并将返回的 Call 对象转换成一个响应对象。在转换过程中,我们会根据响应类型来选择对应的转换器来进行转换。具体的转换实现可以参考 Retrofit 提供的 Converter 接口和 Converter.Factory 接口。

public <T> T execute(Call<T> call) throws IOException {  // ...  Response<T> response = call.execute();  if (response.isSuccessful()) {    return response.body();  } else {    Converter<ResponseBody, ErrorResponse> converter = retrofit.responseBodyConverter(        ErrorResponse.class, new Annotation[0]);    throw new ApiException(converter.convert(response.errorBody()));  }}@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.public <T> T adapt(Call<T> call) {  return (T) new OkHttpCall<>(requestFactory, callFactory, converter, call);}public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {  return nextResponseBodyConverter(null, type, annotations);}public <T> Converter<ResponseBody, T> nextResponseBodyConverter(    @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {  Objects.requireNonNull(type, "type == null");  Objects.requireNonNull(annotations, "annotations == null");  int start = converterFactories.indexOf(skipPast) + 1;  for (int i = start, count = converterFactories.size(); i < count; i++) {    Converter<ResponseBody, ?> converter =        converterFactories.get(i).responseBodyConverter(type, annotations, this);    if (converter != null) {      return (Converter<ResponseBody, T>) converter;    }  }  throw new IllegalArgumentException(      "Could not locate ResponseBody converter for " + type + " with annotations " + Arrays.toString(annotations));}

以上是 Retrofit 中处理响应的核心代码。当我们执行一个请求时,Retrofit 会先将请求转换成 OkHttp 的 Request 对象并发送出去,然后等待响应返回。当响应返回时,Retrofit 会将响应转换成一个响应对象,并将响应对象中的数据转换成我们期望的数据类型。这个过程中,我们可以使用 Retrofit 提供的转换器来自定义数据的转换规则。

下面是一个示例,演示了如何使用 Retrofit 来发送一个 GET 请求并将响应中的 JSON 数据转换成一个 Java 对象:

public interface ApiService {  @GET("users/{user}/repos")  Call<List<Repo>> listRepos(@Path("user") String user);}Retrofit retrofit = new Retrofit.Builder()    .baseUrl("https://api.github.com/")    .addConverterFactory(GsonConverterFactory.create())    .build();ApiService apiService = retrofit.create(ApiService.class);Call<List<Repo>> call = apiService.listRepos("smallmarker");List<Repo> repos = call.execute().body();

在上面的示例中,我们首先使用 Retrofit 构建器创建一个 Retrofit 实例,并指定了请求的基础 URL 和转换器工厂。然后,我们通过调用 create 方法来创建一个 ApiService 的代理对象。最后,我们调用 listRepos 方法来发送一个 GET 请求。

在上面的示例中,我们使用了 Retrofit 的 GsonConverterFactory 来将响应体中的 JSON 数据转换成 Java 对象。具体实现可以查看 Retrofit 提供的 GsonConverterFactory 类。

public final class GsonConverterFactory extends Converter.Factory {  private final Gson gson;  private GsonConverterFactory(Gson gson) {    this.gson = gson;  }  public static GsonConverterFactory create() {    return create(new Gson());  }  public static GsonConverterFactory create(Gson gson) {    if (gson == null) throw new NullPointerException("gson == null");    return new GsonConverterFactory(gson);  }  @Override  public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));    return new GsonResponseBodyConverter<>(gson, adapter);  }  @Override  public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations,                                                                  Annotation[] methodAnnotations, Retrofit retrofit) {    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));    return new GsonRequestBodyConverter<>(gson, adapter);  }}

可以看到,GsonConverterFactory 继承了 Retrofit 的 Converter.Factory 类,并重写了其中的 responseBodyConverter 方法和 requestBodyConverter 方法。在 responseBodyConverter 方法中,我们将响应体中的 JSON 数据转换成 Java 对象,而在 requestBodyConverter 方法中,我们将 Java 对象转换成请求体中的 JSON 数据。

除了 GsonConverterFactory 以外,Retrofit 还提供了其他的转换器,如 JacksonConverterFactory、MoshiConverterFactory 等,我们可以根据需要选择适合自己的转换器。

总的来说,Retrofit 中网络请求和响应处理的核心代码非常简洁明了。我们只需要通过定义接口来描述请求和响应,然后使用 Retrofit 的动态代理机制来将接口转换成一个实际的实现类,并通过 Retrofit 的配置来指定请求和响应的转换器即可。这种方式大大简化了网络请求的流程,使得我们可以更加专注于业务逻辑的处理。

到此,相信大家对“Retrofit网络请求和响应处理源码分析”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Retrofit网络请求和响应处理源码分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Retrofit网络请求和响应处理源码分析

本篇内容主要讲解“Retrofit网络请求和响应处理源码分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Retrofit网络请求和响应处理源码分析”吧!网络请求在使用 Retrofit 发起网
2023-07-05

Retrofit网络请求和响应处理重点分析讲解

这篇文章主要介绍了Retrofit网络请求和响应处理重点分析,在使用Retrofit发起网络请求时,我们可以通过定义一个接口并使用Retrofit的注解来描述这个接口中的请求,Retrofit会自动生成一个实现该接口的代理对象
2023-03-10

Retrofit网络请求框架之注解解析和动态代理

这篇文章主要介绍了Retrofit网络请求框架之注解解析和动态代理,Retrofit是目前Android平台上比较流行的网络请求框架之一,它提供了一种简洁、灵活的方式来处理HTTP请求和响应
2023-03-10

如何用源码分析Struts2请求处理及过程

这期内容当中小编将会给大家带来有关如何用源码分析Struts2请求处理及过程,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。1.1 Struts2请求处理1. 一个请求在Struts2框架中的处理步骤:a)
2023-06-17

Retrofit网络请求框架之注解解析和动态代理方法怎么使用

本篇内容介绍了“Retrofit网络请求框架之注解解析和动态代理方法怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Retrofit是
2023-07-05

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录