【Android】Retrofit创建实例源理

文章目录

    • Retrofit类
    • Builder内部类
    • baseUrl()
    • addConverterFactory()
    • client()

对retrofit的创造实例过程进行源码剖析。

在说之前,介绍一个api,用于判断对象是否为空,然后执行,否则抛出异常,该api在下边很多地方都会出现:

    public static <T> T requireNonNull(T obj, String message) {if (obj == null)throw new NullPointerException(message);return obj;}
//用法:Objects.requireNonNull(obj, "obj == null");

Retrofit类

public final class Retrofit {// 网络请求配置对象(对网络请求接口中方法注解进行解析后得到的对象)// 作用:存储网络请求相关的配置,如网络请求的方法、数据转换器、网络请求适配器、网络请求工厂、基地址等private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();// Call.Factory 实例,用于生产网络请求器,发送网络请求。默认使用的是okhttpfinal okhttp3.Call.Factory callFactory;// API 的基础 URL 地址final HttpUrl baseUrl;// Converter.Factory 实例的列表,用于序列化和反序列化对象final List<Converter.Factory> converterFactories;// CallAdapter.Factory 实例的列表,用于支持不同于 Call 的返回类型final List<CallAdapter.Factory> callAdapterFactories;// 回调方法执行的 Executorfinal @Nullable Executor callbackExecutor;// 是否在创建 Retrofit 实例时进行配置验证final boolean validateEagerly;省略构造函数...

Builder内部类

Builder类的成员变量与Retrofit类的成员变量是对应的,所以Retrofit类的成员变量基本上是通过Builder类的链式调用方法进行配置

public static final class Builder {private Platform platform; // 平台对象private okhttp3.Call.Factory callFactory; // 网络请求的 Call.Factoryprivate HttpUrl baseUrl; // API 的基础 URL 地址private List<Converter.Factory> converterFactories = new ArrayList<>(); // 数据转换器工厂列表private List<CallAdapter.Factory> adapterFactories = new ArrayList<>(); // 适配器工厂列表private Executor callbackExecutor; // 回调方法执行器private boolean validateEagerly; // 是否提前验证// 构造函数public Builder() {this(Platform.get()); // 使用 Platform.get() 初始化 Builder↓}// 获取平台对象static Platform get() {return PLATFORM;}// Builder 的有参构造函数public Builder(Platform platform) {this.platform = platform; // 设置平台对象(Android)// converterFactories是一个存放数据转换器Converter.Factory的数组,下边添加数据转换器converterFactories.add(new BuiltInConverters()); // 初始化数据转换器工厂,// BuiltInConverters是一个内置的数据转换器工厂(继承Converter.Factory类)}
}

那么我们调用构造函数时,就会调用有参构造函数,参数最终是PLATFORM,这个参数在Platform类中已经定义:

class Platform {private static final Platform PLATFORM = findPlatform();static Platform get() {return PLATFORM;}// 查找适合的平台private static Platform findPlatform() {// 判断当前平台是否为 Dalvik(Android)return "Dalvik".equals(System.getProperty("java.vm.name"))? new Android() // 如果是 Android 平台,则返回 Android 对象: new Platform(true); // 否则返回一个默认的 Platform 对象}/*下面的可以不用看,直到内部类Android*/// 是否支持 Java 8 类型private final boolean hasJava8Types;// MethodHandle 的构造函数private final @Nullable Constructor<Lookup> lookupConstructor;// 构造函数Platform(boolean hasJava8Types) {this.hasJava8Types = hasJava8Types;// 初始化 lookupConstructorConstructor<Lookup> lookupConstructor = null;if (hasJava8Types) {try {// 获取 MethodHandle 的构造函数lookupConstructor = Lookup.class.getDeclaredConstructor(Class.class, int.class);lookupConstructor.setAccessible(true); // 设置为可访问} catch (NoClassDefFoundError ignored) {// 对于 Android API 24 或 25,Lookup 类不存在,无法调用默认方法} catch (NoSuchMethodException ignored) {// 假设 JDK 14+,修复了默认方法的问题}}this.lookupConstructor = lookupConstructor;}// 获取默认的回调方法执行器@NullableExecutor defaultCallbackExecutor() {return null;}// 获取默认的网络请求适配器工厂列表List<? extends CallAdapter.Factory> defaultCallAdapterFactories(@Nullable Executor callbackExecutor) {DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);return hasJava8Types? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory): singletonList(executorFactory);}// 获取默认的网络请求适配器工厂列表的大小int defaultCallAdapterFactoriesSize() {return hasJava8Types ? 2 : 1;}// 获取默认的数据转换器工厂列表List<? extends Converter.Factory> defaultConverterFactories() {return hasJava8Types ? singletonList(OptionalConverterFactory.INSTANCE) : emptyList();}// 获取默认的数据转换器工厂列表的大小int defaultConverterFactoriesSize() {return hasJava8Types ? 1 : 0;}// 判断方法是否为默认方法@IgnoreJRERequirement // 仅在 API 24+ 上调用boolean isDefaultMethod(Method method) {return hasJava8Types && method.isDefault();}// 调用默认方法@IgnoreJRERequirement // 仅在 API 26+ 上调用@NullableObject invokeDefaultMethod(Method method, Class<?> declaringClass, Object object, Object... args)throws Throwable {Lookup lookup =lookupConstructor != null? lookupConstructor.newInstance(declaringClass, -1 /* trusted */): MethodHandles.lookup();return lookup.unreflectSpecial(method, declaringClass).bindTo(object).invokeWithArguments(args);}// Android 平台的实现,继承自 Platform。//用于接收服务器返回数据后进行线程切换在主线程显示结果static final class Android extends Platform {Android() {super(Build.VERSION.SDK_INT >= 24);}// 获取默认的回调方法执行器@Overridepublic Executor defaultCallbackExecutor() {return new MainThreadExecutor();// 返回一个默认的回调方法执行器// 作用:切换线程(子->>主线程),并在UI线程中执行回调方法}// 调用默认方法@Nullable@OverrideObject invokeDefaultMethod(Method method, Class<?> declaringClass, Object object, Object... args) throws Throwable {if (Build.VERSION.SDK_INT < 26) {throw new UnsupportedOperationException("Calling default methods on API 24 and 25 is not supported");}return super.invokeDefaultMethod(method, declaringClass, object, args);}// Android 平台的主线程执行器static final class MainThreadExecutor implements Executor {private final Handler handler = new Handler(Looper.getMainLooper());// 该Handler是上面获取的与Android UI线程绑定的Handler @Overridepublic void execute(Runnable r) {handler.post(r);// 在UI线程进行对网络请求返回数据处理等操作。}}}
}

baseUrl()

我们通常调用该函数,填入的都是String类型:

    public Builder baseUrl(String baseUrl) {Objects.requireNonNull(baseUrl, "baseUrl == null");return baseUrl(HttpUrl.get(baseUrl));//转换}

我们可以看到他会跳转到baseUrl(HttpUrl baseUrl)方法,↓

    public Builder baseUrl(HttpUrl baseUrl) {Objects.requireNonNull(baseUrl, "baseUrl == null");List<String> pathSegments = baseUrl.pathSegments();//分割成几个路径碎片//检查是否以'/'结尾,否则抛出异常if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);}this.baseUrl = baseUrl;return this;}

addConverterFactory()

    //存储 Converter.Factoryprivate final List<Converter.Factory> converterFactories = new ArrayList<>();public Builder addConverterFactory(Converter.Factory factory) {converterFactories.add(Objects.requireNonNull(factory, "factory == null"));return this;}

这里用来把转换工厂放入Retrofit的集合中,我们一般在括号内填的是第三方库:GsonConverterFactory.create()

public final class GsonConverterFactory extends Converter.Factory {public static GsonConverterFactory create() {// 调用create()↓return create(new Gson()); ->>步骤2}public static GsonConverterFactory create(Gson gson) {return new GsonConverterFactory(gson); // 创建了一个含有Gson对象实例的GsonConverterFactory ↓}private final Gson gson;private GsonConverterFactory(Gson gson) {if (gson == null) throw new NullPointerException("gson == null");this.gson = gson;}

Retrofit默认使用Gson进行解析

client()

    public Builder client(OkHttpClient client) {return callFactory(Objects.requireNonNull(client, "client == null"));}/*** Specify a custom call factory for creating {@link Call} instances.** <p>Note: Calling {@link #client} automatically sets this value.*/public Builder callFactory(okhttp3.Call.Factory factory) {this.callFactory = Objects.requireNonNull(factory, "factory == null");return this;}//当创建 Retrofit 实例时,会使用这个 callFactory 对象来创建 Call 对象,用于执行网络请求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/205511.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux篇之在Centos环境下搭建Nvidia显卡驱动

一、前提条件 1、首先确认内核版本和发行版本&#xff0c;再确认显卡型号 uname -a // Linux localhost.localdomain 4.18.0-408.el8.x86_64 #1 SMP Mon Jul 18 17:42:52 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux1.2 cat /etc/redhat-release // CentOS Stream release 81.3…

【S2ST】Direct Speech-to-Speech Translation With Discrete Units

【S2ST】Direct Speech-to-Speech Translation With Discrete Units AbstractIntroductionRelated workModelSpeech-to-unit translation (S2UT) modelMultitask learningUnit-based vocoder ExperimentsDataSystem setupBaselineASRMTTTSS2TTransformer Translatotron Evaluat…

Python Jinja2 库的无限可能性

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com Jinja2&#xff0c;作为Python中最流行的模板引擎之一&#xff0c;为开发者提供了强大的工具&#xff0c;用于在Web应用和其他项目中生成动态内容。本文将深入研究 Jinja2 库的各个方面&#xff0c;提供更丰富的…

SQL CREATE INDEX 语句- 提高数据库检索效率的关键步骤

SQL CREATE INDEX 语句 SQL CREATE INDEX 语句用于在表中创建索引。 索引用于比其他方式更快地从数据库中检索数据。用户无法看到索引&#xff0c;它们只是用于加速搜索/查询。 注意&#xff1a; 使用索引更新表比不使用索引更新表需要更多的时间&#xff08;因为索引也需要…

数据科学:Matplotlib、Seaborn笔记

数据科学&#xff1a;Numpy、Pandas 数据科学&#xff1a;Matplotlib、Seaborn笔记 数据科学&#xff1a;Numpy、Pandas、Matplotlib、Seaborn、Scipy、Scikit-Learn 三、Matplotlib1.Matplotlib subplots函数2.tight_layout()函数3.Matplotlib grid()设置网格格式4.fill_bet…

<蓝桥杯软件赛>零基础备赛20周--第9周--前缀和与差分

报名明年4月蓝桥杯软件赛的同学们&#xff0c;如果你是大一零基础&#xff0c;目前懵懂中&#xff0c;不知该怎么办&#xff0c;可以看看本博客系列&#xff1a;备赛20周合集 20周的完整安排请点击&#xff1a;20周计划 每周发1个博客&#xff0c;共20周&#xff08;读者可以按…

大屏可视化基础学习-通用可套用模板【大屏可视化项目案例-15】

🎉🎊🎉 你的技术旅程将在这里启航! 🚀🚀 本专栏包括但不限于大屏可视化、图表可视化等等。订阅专栏用户在文章底部可下载对应案例源码以供大家深入的学习研究。 🎓 每一个案例都会提供完整代码和详细的讲解,不论你是初学者还是资深开发者,这里都有适合你的内容。…

从零开始的c语言日记day41——自定义类型结构体

一、结构体的声明 1.1结构的基础知识 结构是一些值的集合&#xff0c;这些值称为成员变量。结构的每个成员可以是不同类型的变量。 Tag结构体标签 Member-list成员列表-里面可以有很多成员 Variable-list变量列表 结构体类型的定义方式 S1&#xff0c;s2是struct stu类型的…

黑苹果之显卡篇

一、什么是显卡 显卡GPU&#xff08;Video card、Display card、Graphics card、Video adapter&#xff09;是个人计算机基础的组成部分之一&#xff0c;将计算机系统需要的显示信息进行转换驱动显示器&#xff0c;并向显示器提供逐行或隔行扫描信号&#xff0c;控制显示器的正…

python数据分析

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 pandas统计分析基础实训 实训1 读取并查看某地区房屋销售数据的基本信息1. 训练要点2. 需求说明3.实现思路及步骤 实训2 提取房屋售出时间信息并描述房屋价格信息1. 训练要点…

数据结构 图的广度优先搜索和深度优先搜索

一、广度优先搜索 广度优先搜索等价于树的层次遍历&#xff0c;将起点的每一层进行遍历 当这一层结点全部被遍历完时&#xff0c;再遍历下一层次&#xff0c;从图中可以根据距离遍历起点的长度进行层次选择 例&#xff1a; 以a结点作为开始结点 a的下一层次有b c e三个结点 所以…

nginx 一键切换停机维护页面 —— 筑梦之路

背景说明 进行停机维护或者系统升级等操作&#xff0c;会影响到用户使用&#xff0c;如果停机维护期间用户未看到停机维护的通知&#xff0c;仍去访问系统&#xff0c;会提示默认不太友好的访问错误界面 &#xff0c;这时如果在维护的时候直接展示停机公告的具体信息&#xff0…

Spark Structured Streaming使用教程

文章目录 1、输入数据源2、输出模式3、sink输出结果4、时间窗口4.1、时间窗口4.2、时间水印&#xff08;Watermarking&#xff09; 5、使用例子 Structured Streaming是一个基于Spark SQL引擎的可扩展和容错流处理引擎&#xff0c;Spark SQL引擎将负责增量和连续地运行它&#…

Spring Security 自定义异常失效?从源码分析到解决方案

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

JAVA 企业面试题

JAVA 企业面试题 面试题集 面试题集共分为以下十部分&#xff1a; 一、 Core Java&#xff1a; 1 — 95 题 1 — 24 页 基础及语法&#xff1a; 1 — 61 题 1 — 13 页 异常&#xff1a; 62 — 69 题 13 — 15 页 集合&#xff1a; 70 — 80 题 15 — 18 页 线程&#xff1a…

使用阿里巴巴同步工具DataX实现Mysql与ElasticSearch(ES)数据同步

一、Linux环境要求 二、准备工作 2.1 Linux安装jdk 2.2 linux安装python 2.3 下载DataX&#xff1a; 三、DataX压缩包导入&#xff0c;解压缩 四、编写同步Job 五、执行Job 六、定时更新 6.1 创建定时任务 6.2 提交定时任务 6.3 查看定时任务 七、增量更新思路 一、Linux环境要…

微信小程序js数组对象根据某个字段排序

一、排序栗子 注: 属性字段需要进行转换,如String类型或者Number类型 //升序排序 首元素(element1)在前 降序则(element1)元素在后 data data.sort((element1, element2) >element1.属性 - element2.属性 ); 二、代码 Page({/*** 页面的初始数据*/data: {user:…

每日一练 | 华为认证真题练习Day144

1、DHCPv6无状态自动分配方案中&#xff0c;主机不需要发送任何DHCPv6报文。 A. 对 B. 错 2、IPv4最后一个选项字段&#xff08;option&#xff09;是可变长的可选信息&#xff0c;该字段最大长度为&#xff1f; A. 40B B. 20B C. 60B D. 10B 3、关于ARP协议的作用和报文…

SpringSecurity安全授权

目录 前言 正文 1.基本流程 2.基本用法 3.配置项 4.HttpSecurity 方式和内存认证方式 5.认证流程 6.基于数据库查询的登录验证 7.多种角色权限认证 8.自定义权限认证 总结 前言 安全对于任何系统来说都是非常重要的&#xff0c;权限的分配和管理一直都是开发者需…

C语言——输出菱形

法一&#xff1a; #include<stdio.h> #define N 7 //假设输出7层菱形 int main(){int i;//i控制第几行 int j;//j控制每一行空格的循环个数 int k;//k控制每一行*的循环次数 for(i1;i<4;i){//将图形分为两部分,前四行(第一部分) for(j1;j<4-i;j){//输出第i行的…