2、创建Retrofit并生成API的实现(注意:方法上面的注解表示请求的接口部分,返回类型是请求的返回值类型,方法的参数即是请求的参数)
// 1.Retrofit构建过程
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(“https://api.github.com/”)
.build();
// 2.创建网络请求接口类实例过程
GitHubService service = retrofit.create(GitHubService.class);
复制代码
3、调用API方法,生成Call,执行请求
// 3.生成并执行请求过程
Call<List> repos = service.listRepos(“octocat”);
repos.execute() or repos.enqueue()
复制代码
Retrofit的基本使用流程很简洁,但是简洁并不代表简单,Retrofit为了实现这种简洁的使用流程,内部使用了优秀的架构设计和大量的设计模式,在我分析过Retrofit最新版的源码和大量优秀的Retrofit源码分析文章后,我发现,要想真正理解Retrofit内部的核心源码流程和设计思想,首先,需要对这九大设计模式有一定的了解,如下:
1.Retrofit构建过程
建造者模式、工厂方法模式
2.创建网络请求接口实例过程
外观模式、代理模式、单例模式、策略模式、装饰模式(建造者模式)
3.生成并执行请求过程
适配器模式(代理模式、装饰模式)
复制代码
其次,需要对OKHttp源码有一定的了解,如果不了解的可以看看这篇Android主流三方库源码分析(一、深入理解OKHttp源码)。最后,让我们按以上流程去深入Retrofit源码内部,领悟它带给我们的设计之美。
二、Retrofit构建过程
1、Retrofit核心对象解析
首先Retrofit中有一个全局变量非常关键,在V2.5之前的版本,使用的是LinkedHashMap(),它是一个网络请求配置对象,是由网络请求接口中方法注解进行解析后得到的。
public final class Retrofit {
// 网络请求配置对象,存储网络请求相关的配置,如网络请求的方法、数据转换器、网络请求适配器、网络请求工厂、基地址等
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
复制代码
Retrofit使用了建造者模式通过内部类Builder类建立一个Retrofit实例,如下:
public static final class Builder {
// 平台类型对象(Platform -> Android)
private final Platform platform;
// 网络请求工厂,默认使用OkHttpCall(工厂方法模式)
private @Nullable okhttp3.Call.Factory callFactory;
// 网络请求的url地址
private @Nullable HttpUrl baseUrl;
// 数据转换器工厂的集合
private final List<Converter.Factory> converterFactories = new ArrayList<>();
// 网络请求适配器工厂的集合,默认是ExecutorCallAdapterFactory
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
// 回调方法执行器,在 Android 上默认是封装了 handler 的 MainThreadExecutor, 默认作用是:切换线程(子线程 -> 主线程)
private @Nullable Executor callbackExecutor;
// 一个开关,为true则会缓存创建的ServiceMethod
private boolean validateEagerly;
复制代码
2、Builder内部构造
下面看看Builder内部构造做了什么。
public static final class Builder {
…
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}
…
}
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
// 使用JVM加载类的方式判断是否是Android平台
Class.forName(“android.os.Build”);
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
// 同时支持Java平台
Class.forName(“java.util.Optional”);
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
static class Android extends Platform {
…
@Override public Executor defaultCallbackExecutor() {
//切换线程(子线程 -> 主线程)
return new MainThreadExecutor();
}
// 创建默认的网络请求适配器工厂,如果是Android7.0或Java8上,则使
// 用了并发包中的CompletableFuture保证了回调的同步
// 在Retrofit中提供了四种CallAdapterFactory(策略模式):
// ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、
// va8CallAdapterFactory、RxJavaCallAdapterFactory
@Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor);
return Build.VERSION.SDK_INT >= 24
-
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
- singletonList(executorFactory);
}
…
@Override List<? extends Converter.Factory> defaultConverterFactories() {
return Build.VERSION.SDK_INT >= 24
-
? singletonList(OptionalConverterFactory.INSTANCE)
- Collections.<Converter.Factory>emptyList();
}
…
static class MainThreadExecutor implements Executor {
// 获取Android 主线程的Handler
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
// 在UI线程对网络请求返回数据处理
handler.post®;
}
}
}
复制代码
可以看到,在Builder内部构造时设置了默认Platform、callAdapterFactories和callbackExecutor。
3、添加baseUrl
很简单,就是将String类型的url转换为OkHttp的HttpUrl过程如下:
/**
-
Set the API base URL.
-
@see #baseUrl(HttpUrl)
*/
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, “baseUrl == null”);
return baseUrl(HttpUrl.get(baseUrl));
}
public Builder baseUrl(HttpUrl baseUrl) {
checkNotNull(baseUrl, “baseUrl == null”);
List pathSegments = baseUrl.pathSegments();
if (!“”.equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
复制代码
4、添加GsonConverterFactory
首先,看到GsonConverterFactory.creat()的源码。
public final class GsonConverterFactory extends Converter.Factory {
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);
}
private final Gson gson;
// 创建了一个含有Gson对象实例的GsonConverterFactory
private GsonConverterFactory(Gson gson) {
this.gson = gson;
}
复制代码
然后,看看addConverterFactory()方法内部。
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, “factory null”));
return this;
}
复制代码
可知,这一步是将一个含有Gson对象实例的GsonConverterFactory放入到了数据转换器工厂converterFactories里。
5、build过程
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException(“Base URL required.”);
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
// 默认使用okhttp
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
// Android默认的callbackExecutor
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the defaultCall adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
// 添加默认适配器工厂在集合尾部
callAdapterFactories.addAll(platform.defaultCallAdapterFactorisca llbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters thatconsumeall types.
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories();
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
复制代码
可以看到,最终我们在Builder类中看到的6大核心对象都已经配置到Retrofit对象中了。
三、创建网络请求接口实例过程
retrofit.create()使用了外观模式和代理模式创建了网络请求的接口实例,我们分析下create方法。
public T create(final Class service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
// 判断是否需要提前缓存ServiceMethod对象
eagerlyValidateMethods(service);
}
// 使用动态代理拿到请求接口所有注解配置后,创建网络请求接口实例
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
复制代码
继续看看loadServiceMethod的内部流程
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
// 解析注解配置得到了ServiceMethod
result = ServiceMethod.parseAnnotations(this, method);
// 可以看到,最终加入到ConcurrentHashMap缓存中
serviceMethodCache.put(method, result);
}
}
return result;
}
abstract class ServiceMethod {
static ServiceMethod parseAnnotations(Retrofit retrofit, Method method) {
// 通过RequestFactory解析注解配置(工厂模式、内部使用了建造者模式)
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
“Method return type must not include a type variable or wildcard: %s”, returnType);
}
if (returnType == void.class) {
throw methodError(method, “Service methods cannot return void.”);
}
// 最终是通过HttpServiceMethod构建的请求方法
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract T invoke(Object[] args);
}
复制代码
以下为请求构造核心流程
根据RequestFactory#Builder构造方法和parseAnnotations方法的源码,可知的它的作用就是用来解析注解配置的。
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
// 获取网络请求接口方法里的注释
this.methodAnnotations = method.getAnnotations();
// 获取网络请求接口方法里的参数类型
this.parameterTypes = method.getGenericParameterTypes();
// 获取网络请求接口方法里的注解内容
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
复制代码
接着看HttpServiceMethod.parseAnnotations()的内部流程。
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
//1.根据网络请求接口方法的返回值和注解类型,
// 从Retrofit对象中获取对应的网络请求适配器
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit,method);
// 得到响应类型
Type responseType = callAdapter.responseType();
…
//2.根据网络请求接口方法的返回值和注解类型从Retrofit对象中获取对应的数据转换器
Converter<ResponseBody, ResponseT>responseConverter =
createResponseConverter(retrofit,method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
return newHttpServiceMethod<>(requestFactory, callFactory, callAdapter,responseConverter);
}
复制代码
1.createCallAdapter(retrofit, method)
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method) {
// 获取网络请求接口里方法的返回值类型
Type returnType = method.getGenericReturnType();
// 获取网络请求接口接口里的注解
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, “Unable to create call adapter for %s”, returnType);
}
}
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
如何做好面试突击,规划学习方向?
面试题集可以帮助你查漏补缺,有方向有针对性的学习,为之后进大厂做准备。但是如果你仅仅是看一遍,而不去学习和深究。那么这份面试题对你的帮助会很有限。最终还是要靠资深技术水平说话。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。建议先制定学习计划,根据学习计划把知识点关联起来,形成一个系统化的知识体系。
学习方向很容易规划,但是如果只通过碎片化的学习,对自己的提升是很慢的。
我搜集整理过这几年字节跳动,以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。
在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。
在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算