- 通过 网络请求执行器 发送网络请求
- 通过 数据转换器 解析服务器返回的数据
- 通过 回调执行器 切换线程(子线程 ->>主线程)
- 用户在主线程处理返回结果
下面介绍上面提到的几个角色
特别注意:因下面的 源码分析 是根据 使用步骤 逐步带你debug进去的,所以必须先看文章这是一份很详细的 Retrofit 2.0 使用教程(含实例讲解)
4.2 源码分析
先来回忆Retrofit的使用步骤:
- 创建Retrofit实例
- 创建 网络请求接口实例 并 配置网络请求参数
- 发送网络请求
封装了 数据转换、线程切换的操作
- 处理服务器返回的数据
4.2.1 创建Retrofit实例
a. 使用步骤
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(“http://fanyi.youdao.com/”)
.addConverterFactory(GsonConverterFactory.create())
.build();
复制代码
b. 源码分析
Retrofit实例是使用建造者模式通过Builder类进行创建的
建造者模式:将一个复杂对象的构建与表示分离,使得用户在不知道对象的创建细节情况下就可以直接创建复杂的对象。具体请看文章:建造者模式(Builder Pattern)- 最易懂的设计模式解析
接下来,我将分五个步骤对创建Retrofit实例进行逐步分析
步骤1
<-- 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(list)
// 作用:创建的新对象能够对list数据进行访问,但不可通过该对象对list集合中的元素进行修改
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
…
// 仅贴出关键代码
}
复制代码
成功建立一个Retrofit对象的标准:配置好Retrofit类里的成员变量,即配置好:
serviceMethod
:包含所有网络请求信息的对象baseUrl
:网络请求的url地址callFactory
:网络请求工厂adapterFactories
:网络请求适配器工厂的集合converterFactories
:数据转换器工厂的集合callbackExecutor
:回调方法执行器
所谓xxxFactory
、“xxx工厂”其实是设计模式中工厂模式的体现:将“类实例化的操作”与“使用对象的操作”分开,使得使用者不用知道具体参数就可以实例化出所需要的“产品”类。
具体请看我写的文章 简单工厂模式(SimpleFactoryPattern)- 最易懂的设计模式解析 工厂方法模式(Factory Method)- 最易懂的设计模式解析 抽象工厂模式(Abstract Factory)- 最易懂的设计模式解析
这里详细介绍一下:CallAdapterFactory
:该Factory
生产的是CallAdapter
,那么CallAdapter
又是什么呢?
CallAdapter
详细介绍
- 定义:网络请求执行器(Call)的适配器
- Call在Retrofit里默认是
OkHttpCall
- 在Retrofit中提供了四种CallAdapterFactory: ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory
- 作用:将默认的网络请求执行器(OkHttpCall)转换成适合被不同平台来调用的网络请求执行器形式
- 如:一开始
Retrofit
只打算利用OkHttpCall
通过ExecutorCallbackCall
切换线程;但后来发现使用Rxjava
更加方便(不需要Handler来切换线程)。想要实现Rxjava
的情况,那就得使用RxJavaCallAdapterFactoryCallAdapter
将OkHttpCall
转换成Rxjava(Scheduler)
:
// 把response封装成rxjava的Observeble,然后进行流式操作
Retrofit.Builder.addCallAdapterFactory(newRxJavaCallAdapterFactory().create());
// 关于RxJava的使用这里不作更多的展开
复制代码
- Retrofit还支持java8、Guava平台。
- 好处:用最小代价兼容更多平台,即能适配更多的使用场景
所以,接下来需要分析的步骤2、步骤3、步骤4、步骤4的目的是配置好上述所有成员变量
步骤2
我们先来看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®;
// 该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类分析完毕,总结:Builder设置了默认的
- 平台类型对象:Android
- 网络请求适配器工厂:CallAdapterFactory
CallAdapter用于对原始Call进行再次封装,如Call到Observable
- 数据转换器工厂: converterFactory
- 回调执行器:callbackExecutor
特别注意,这里只是设置了默认值,但未真正配置到具体的Retrofit类的成员变量当中
步骤3
还是按部就班按步骤来观看
<-- 步骤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 pathSegments = baseUrl.pathSegments();
// 检测最后一个碎片来检查URL参数是不是以"/“结尾
// 不是就抛出异常
if (!”".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
- 至此,步骤3分析完毕
- 总结:baseUrl()用于配置Retrofit类的网络请求url地址
将传入的String类型url转化为适合OKhttp的HttpUrl类型的url
步骤4
我们从里往外看,即先看GsonConverterFactory.creat()
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.creat()是创建了一个含有Gson对象实例的GsonConverterFactory,并返回给
addConverterFactory()
- 接下来继续看:
addConverterFactory()
// 将上面创建的GsonConverterFactory放入到 converterFactories数组
// 在第二步放入一个内置的数据转换器工厂BuiltInConverters()后又放入了一个GsonConverterFactory
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, “factory == null”));
return this;
}
- 至此,分析完毕
- 总结:步骤4用于创建一个含有Gson对象实例的GsonConverterFactory并放入到数据转换器工厂converterFactories里
- 即Retrofit默认使用Gson进行解析
- 若使用其他解析方式(如Json、XML或Protocobuf),也可通过自定义数据解析器来实现(必须继承 Converter.Factory)
步骤5
终于到了最后一个步骤了。
public Retrofit build() {
<-- 配置网络请求执行器(callFactory)–>
okhttp3.Call.Factory callFactory = this.callFactory;
// 如果没指定,则默认使用okhttp
// 所以Retrofit默认使用okhttp进行网络请求
if (callFactory == null) {
callFactory = new OkHttpClient();
}
<-- 配置回调方法执行器(callbackExecutor)–>
Executor callbackExecutor = this.callbackExecutor;
// 如果没指定,则默认使用Platform检测环境时的默认callbackExecutor
// 即Android默认的callbackExecutor
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
<-- 配置网络请求适配器工厂(CallAdapterFactory)–>
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
// 向该集合中添加了步骤2中创建的CallAdapter.Factory请求适配器(添加在集合器末尾)
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// 请求适配器工厂集合存储顺序:自定义1适配器工厂、自定义2适配器工厂…默认适配器工厂(ExecutorCallAdapterFactory)
<-- 配置数据转换器工厂:converterFactory -->
// 在步骤2中已经添加了内置的数据转换器BuiltInConverters()(添加到集合器的首位)
// 在步骤4中又插入了一个Gson的转换器 - GsonConverterFactory(添加到集合器的首二位)
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
// 数据转换器工厂集合存储的是:默认数据转换器工厂( BuiltInConverters)、自定义1数据转换器工厂(GsonConverterFactory)、自定义2数据转换器工厂…
// 注:
//1. 获取合适的网络请求适配器和数据转换器都是从adapterFactories和converterFactories集合的首位-末位开始遍历
// 因此集合中的工厂位置越靠前就拥有越高的使用权限
// 最终返回一个Retrofit的对象,并传入上述已经配置好的成员变量
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
复制代码
- 至此,步骤5分析完毕
- 总结:在最后一步中,通过前面步骤设置的变量,将Retrofit类的所有成员变量都配置完毕。
- 所以,成功创建了Retrofit的实例
总结
Retrofit使用建造者模式通过Builder类建立了一个Retrofit实例,具体创建细节是配置了:
- 平台类型对象(Platform - Android)
- 网络请求的url地址(baseUrl)
- 网络请求工厂(callFactory)
默认使用OkHttpCall
- 网络请求适配器工厂的集合(adapterFactories)
本质是配置了网络请求适配器工厂- 默认是ExecutorCallAdapterFactory
- 数据转换器工厂的集合(converterFactories)
本质是配置了数据转换器工厂
- 回调方法执行器(callbackExecutor)
默认回调方法执行器作用是:切换线程(子线程 - 主线程)
由于使用了建造者模式,所以开发者并不需要关心配置细节就可以创建好Retrofit实例,建造者模式get。
在创建Retrofit对象时,你可以通过更多更灵活的方式去处理你的需求,如使用不同的Converter、使用不同的CallAdapter,这也就提供了你使用RxJava来调用Retrofit的可能
2. 创建网络请求接口的实例
2.1 使用步骤
<-- 步骤1:定义接收网络数据的类 -->
<-- JavaBean.java -->
public class JavaBean {
… // 这里就不介绍了
}
<-- 步骤2:定义网络请求的接口类 -->
<-- AccessApi.java -->
public interface AccessApi {
// 注解GET:采用Get方法发送网络请求
// Retrofit把网络请求的URL分成了2部分:1部分baseurl放在创建Retrofit对象时设置;另一部分在网络请求接口设置(即这里)
// 如果接口里的URL是一个完整的网址,那么放在创建Retrofit对象时设置的部分可以不设置
@GET(“openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car”)
// 接受网络请求数据的方法
Call getCall();
// 返回类型为Call<*>,*是解析得到的数据类型,即JavaBean
}
<-- 步骤3:在MainActivity创建接口类实例 -->
AccessApi NetService = retrofit.create(AccessApi.class);
<-- 步骤4:对发送请求的url进行封装,即生成最终的网络请求对象 -->
Call call = NetService.getCall();
复制代码
2.2 源码分析
- 结论:Retrofit是通过外观模式 & 代理模式 使用create()方法创建网络请求接口的实例(同时,通过网络请求接口里设置的注解进行了网络请求参数的配置)
- 外观模式:定义一个统一接口,外部与通过该统一的接口对子系统里的其他接口进行访问。具体请看:外观模式(Facade Pattern) - 最易懂的设计模式解析
- 代理模式:通过访问代理对象的方式来间接访问目标对象。具体请看:代理模式(Proxy Pattern)- 最易懂的设计模式解析
- 下面主要分析步骤3和步骤4:
<-- 步骤3:在MainActivity创建接口类实例 -->
AccessApi NetService = retrofit.create(NetService.class);
<-- 步骤4:对发送请求的url进行封装,即生成最终的网络请求对象 -->
Call call = NetService.getCall();
复制代码
步骤3讲解:AccessApi NetService = retrofit.create(NetService.class);
public T create(final Class service) {
if (validateEagerly) {
// 判断是否需要提前验证
eagerlyValidateMethods(service);
// 具体方法作用:
// 1. 给接口中每个方法的注解进行解析并得到一个ServiceMethod对象
// 2. 以Method为键将该对象存入LinkedHashMap集合中
// 特别注意:如果不是提前验证则进行动态解析对应方法(下面会详细说明),得到一个ServiceMethod对象,最后存入到LinkedHashMap集合中,类似延迟加载(默认)
}
// 创建了网络请求接口的动态代理对象,即通过动态代理创建网络请求接口的实例 (并最终返回)
// 该动态代理是为了拿到网络请求接口实例上所有注解
return (T) Proxy.newProxyInstance(
service.getClassLoader(), // 动态生成接口的实现类
new Class<?>[] { service }, // 动态创建实例
new InvocationHandler() { // 将代理类的实现交给 InvocationHandler类作为具体的实现(下面会解释)
private final Platform platform = Platform.get();
// 在 InvocationHandler类的invoke()实现中,除了执行真正的逻辑(如再次转发给真正的实现类对象),还可以进行一些有用的操作
// 如统计执行时间、进行初始化和清理、对接口调用进行检查等。
@Override
public Object invoke(Object proxy, Method method, Object… args)
throws Throwable {
// 下面会详细介绍 invoke()的实现
// 即下面三行代码
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
// 特别注意
// return (T) roxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler)
// 可以解读为:getProxyClass(loader, interfaces) .getConstructor(InvocationHandler.class).newInstance(invocationHandler);
// 即通过动态生成的代理类,调用interfaces接口的方法实际上是通过调用InvocationHandler对象的invoke()来完成指定的功能
// 先记住结论,在讲解步骤4的时候会再次详细说明
<-- 关注点1:eagerlyValidateMethods() -->
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) { loadServiceMethod(method); }
// 将传入的ServiceMethod对象加入LinkedHashMap<Method, ServiceMethod>集合
// 使用LinkedHashMap集合的好处:lruEntries.values().iterator().next()获取到的是集合最不经常用到的元素,提供了一种Lru算法的实现
}
}
创建网络接口实例用了外观模式 & 代理模式:
使用外观模式进行访问,里面用了代理模式
1. 外观模式
-
外观模式:定义一个统一接口,外部与通过该统一的接口对子系统里的其他接口进行访问。具体请看:外观模式(Facade Pattern) - 最易懂的设计模式解析
-
Retrofit对象的外观(门店) =
retrofit.create()
-
通过这一外观方法就可以在内部调用各个方法创建网络请求接口的实例和配置网络请求参数
大大降低了系统的耦合度
2. 代理模式
- 代理模式:通过访问代理对象的方式来间接访问目标对象
分为静态代理 & 动态代理:
- 静态代理:代理类在程序运行前已经存在的代理方式
- 动态代理:代理类在程序运行前不存在、运行时由程序动态生成的代理方式 具体请看文章代理模式(Proxy Pattern)- 最易懂的设计模式解析
return (T) roxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler)
通过代理模式中的动态代理模式,动态生成网络请求接口的代理类,并将代理类的实例创建交给InvocationHandler类
作为具体的实现,并最终返回一个动态代理对象。
生成实例过程中含有生成实现类的缓存机制(单例模式),下面会详细分析
使用动态代理的好处:
- 当
NetService
对象调用getCall()
接口中方法时会进行拦截,调用都会集中转发到 InvocationHandler#invoke (),可集中进行处理 - 获得网络请求接口实例上的所有注解
- 更方便封装ServiceMethod
下面看源码分析
下面将详细分析InvocationHandler类 # invoke()
里的具体实现
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override
public Object invoke(Object proxy, Method method, Object… args)
throws Throwable {
// 将详细介绍下面代码
// 关注点1
// 作用:读取网络请求接口里的方法,并根据前面配置好的属性配置serviceMethod对象
ServiceMethod serviceMethod = loadServiceMethod(method);
// 关注点2
// 作用:根据配置好的serviceMethod对象创建okHttpCall对象
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
// 关注点3
// 作用:调用OkHttp,并根据okHttpCall返回rejava的Observe对象或者返回Call
return serviceMethod.callAdapter.adapt(okHttpCall);
}
复制代码
下面将详细介绍3个关注点的代码。
关注点1: ServiceMethod serviceMethod = loadServiceMethod(method);
<-- loadServiceMethod(method)方法讲解 -->
// 一个 ServiceMethod 对象对应于网络请求接口里的一个方法
// loadServiceMethod(method)负责加载 ServiceMethod:
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
// 设置线程同步锁
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
// ServiceMethod类对象采用了单例模式进行创建
// 即创建ServiceMethod对象前,先看serviceMethodCache有没有缓存之前创建过的网络请求实例
// 若没缓存,则通过建造者模式创建 serviceMethod 对象
if (result == null) {
// 下面会详细介绍ServiceMethod生成实例的过程
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
// 这里就是上面说的创建实例的缓存机制:采用单例模式从而实现一个 ServiceMethod 对象对应于网络请求接口里的一个方法
// 注:由于每次获取接口实例都是传入 class 对象
// 而 class 对象在进程内单例的,所以获取到它的同一个方法 Method 实例也是单例的,所以这里的缓存是有效的。
下面,我将分3个步骤详细分析serviceMethod
实例的创建过程:
步骤1:ServiceMethod类
构造函数
<-- ServiceMethod 类 -->
public final class ServiceMethod {
final okhttp3.Call.Factory callFactory; // 网络请求工厂
final CallAdapter<?> callAdapter;
// 网络请求适配器工厂
// 具体创建是在new ServiceMethod.Builder(this, method).build()最后的build()中
// 下面会详细说明
private final Converter<ResponseBody, T> responseConverter;
// Response内容转换器
// 作用:负责把服务器返回的数据(JSON或者其他格式,由 ResponseBody 封装)转化为 T 类型的对象;
private final HttpUrl baseUrl; // 网络请求地址
private final String relativeUrl; // 网络请求的相对地址
private final String httpMethod; // 网络请求的Http方法
private final Headers headers; // 网络请求的http请求头 键值对
private final MediaType contentType; // 网络请求的http报文body的类型
private final ParameterHandler<?>[] parameterHandlers;
// 方法参数处理器
// 作用:负责解析 API 定义时每个方法的参数,并在构造 HTTP 请求时设置参数;
// 下面会详细说明
// 说明:从上面的成员变量可以看出,ServiceMethod对象包含了访问网络的所有基本信息
<-- ServiceMethod 类的构造函数 -->
// 作用:传入各种网络请求参数
ServiceMethod(Builder builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.responseConverter = builder.responseConverter;
this.baseUrl = builder.retrofit.baseUrl();
this.relativeUrl = builder.relativeUrl;
this.httpMethod = builder.httpMethod;
this.headers = builder.headers;
this.contentType = builder.contentType; .
this.hasBody = builder.hasBody; y
this.isFormEncoded = builder.isFormEncoded;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
最后送福利了,现在关注我并且加入群聊可以获取包含源码解析,自定义View,动画实现,架构分享等。
内容难度适中,篇幅精炼,每天只需花上十几分钟阅读即可。
大家可以跟我一起探讨,欢迎加群探讨,有flutter—底层开发—性能优化—移动架构—资深UI工程师 —NDK相关专业人员和视频教学资料,还有更多面试题等你来拿
点击GitHub领取
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-z1KJHCHM-1711173361698)]
[外链图片转存中…(img-00tpssMZ-1711173361699)]
[外链图片转存中…(img-Q1PvQagR-1711173361699)]
[外链图片转存中…(img-uXXTApNS-1711173361700)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-3x3HS90F-1711173361700)]
最后送福利了,现在关注我并且加入群聊可以获取包含源码解析,自定义View,动画实现,架构分享等。
内容难度适中,篇幅精炼,每天只需花上十几分钟阅读即可。
大家可以跟我一起探讨,欢迎加群探讨,有flutter—底层开发—性能优化—移动架构—资深UI工程师 —NDK相关专业人员和视频教学资料,还有更多面试题等你来拿
点击GitHub领取
[外链图片转存中…(img-ZDgUxfyI-1711173361700)]