Android主流三方库源码分析:Retrofit(1),android插件化开发指南

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移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

如何做好面试突击,规划学习方向?

面试题集可以帮助你查漏补缺,有方向有针对性的学习,为之后进大厂做准备。但是如果你仅仅是看一遍,而不去学习和深究。那么这份面试题对你的帮助会很有限。最终还是要靠资深技术水平说话。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。建议先制定学习计划,根据学习计划把知识点关联起来,形成一个系统化的知识体系。

学习方向很容易规划,但是如果只通过碎片化的学习,对自己的提升是很慢的。

我搜集整理过这几年字节跳动,以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节

img

在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节

img

在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

  • 20
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值