Android-三方框架的源码

ARouter

Arouter的整体思路是moduelA通过中间人ARouter把路由信息的存到仓库WareHouse;moduleB发起路由时,再通过中间人ARouter从仓库WareHouse取出路由信息,这要就实现了没有依赖的两者之间的跳转与通信。其中涉及Activity的跳转、服务provider的获取、拦截器的处理等。

路由元信息是怎么收集的?
跳转Activity最终必定是走到了 startActivity(intent)方法,而intent是一般需要目标Activity的Class,构建PostCard,继承自路由元信息 RouteMeta,参数group是path的第一级,group的作用是作为路由的默认分组。Warehouse意为仓库,用于存放被 @Route、@Interceptor注释的 路由相关的信息,也就是我们关注的destination等信息。由于进行activity跳转需要目标Activity的class对象来构建intent,所以必须有一个中间人,把路径"/test/activity"翻译成Activity的class对象,然后moduleB才能实现跳转。 Warehouse,它存着所有路由信息。
Warehouse存了哪些信息呢?

class Warehouse {//所有IRouteGroup实现类的class对象,是在ARouter初始化中赋值,key是path第一级//(IRouteGroup实现类是编译时生成,代表一个组,即path第一级相同的所有路由,包括Activity和Provider服务)static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>(); //所有路由元信息,是在completion中赋值,key是path//首次进行某个路由时就会加载整个group的路由,即IRouteGroup实现类中所有路由信息。包括Activity和Provider服务static Map<String, RouteMeta> routes = new HashMap<>();//所有服务provider实例,在completion中赋值,key是IProvider实现类的classstatic Map<Class, IProvider> providers = new HashMap<>();//所有provider服务的元信息(实现类的class对象),是在ARouter初始化中赋值,key是IProvider实现类的全类名。//主要用于使用IProvider实现类的class发起的获取服务的路由,例如ARouter.getInstance().navigation(HelloService.class)static Map<String, RouteMeta> providersIndex = new HashMap<>();//所有拦截器实现类的class对象,是在ARouter初始化时收集到,key是优先级static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("...");//所有拦截器实例,是在ARouter初始化完成后立即创建static List<IInterceptor> interceptors = new ArrayList<>();
...
}

groupsIndex,所有路由组元信息。是所有IRouteGroup实现类的class对象,是在ARouter初始化中赋值,key是path第一级。IRouteGroup实现类是编译时生成,代表一个组,即path第一级相同的所有路由,包括Activity和Provider服务)。
routes,所有路由元信息。是在LogisticsCenter.completion中赋值,key是path。首次进行某个路由时就会加载整个group的路由,即IRouteGroup实现类中所有路由信息。包括Activity和Provider服务
providers,所有服务provider实例。在LogisticsCenter.completion中赋值,key是IProvider实现类的class
providersIndex,所有provider服务元信息(实现类的class对象)。是在ARouter初始化中赋值,key是IProvider实现类的全类名。用于使用IProvider实现类class发起的获取服务的路由,例如ARouter.getInstance().navigation(HelloService.class)
interceptorsIndex,所有拦截器实现类class对象。是在ARouter初始化时收集到,key是优先级
interceptors,所有拦截器实例。是在ARouter初始化完成后立即创建
其中groupsIndex、providersIndex、interceptorsIndex是ARouter初始化时就准备好的基础信息,为业务中随时发起路由操作(Activity跳转、服务获取、拦截器处理)做好准备。

ARouter 框架的设计是它默认会将注解中注册path路径中第一个路由层级 (例如 "/trade/homePage"中的trade)作为该路由信息所的Group, 相同Group路径的路由信息会合并到最终生成的同一个类 的注册函数中进行同步注册。在大型项目中,对于复杂业务线同一个Group下可能包含上百个注册信息,注册逻辑执行过程耗时较长。

ARouter在编译时生成的帮助类PluginLaunch、RegisterTransform、ScanUtil这三个类,是用于对所有使用@Route、@Interceptor注解的类信息的分组和收集,编译运行时对路由信息仓库Warehouse的填充和使用。这里涉及到的是Annotation Process Tool(APT)技术,即注解处理工具。 除了运行时查找dex,还可以在编译时扫描帮助类信息,并且直接在物流中心LogisticsCenter loadRouterMap()方法中直接插入使用帮助类的代码,这里涉及 Android Gradle Plugin(AGP)技术,即Android的gradle插件相关技术。Android官方的AGP中提供了一个API——Transform,在class文件转为dex文件之前,这个节点可以拿到参与构建的所有class文件,在Transform的中拿到所有class文件后,通过ASM字节码操作框架,使用ASM对源码生产class文件和三方jar中的class文件进行扫描,找到所有帮助类,也就是PluginLaunch、RegisterTransform、ScanUtil这三个类,PluginLaunch,就是自定义的Gradle插件,然后注册了自定义的RegisterTransform。RegisterTransform中的registerList保存着的是各个帮助类的接口。RegisterTransform是自定义的Transform,transform方法会在gradle的执行阶段执行——源码生成class文件之后、class被打进dex文件之前。具体逻辑就是 扫描全部jar(三方库中的class文件)、扫描全部目录(源码生成的class文件),拿到所有目标帮助类,在 LogisticsCenter#loadRouterMap()中插入代码。

Arouter怎么找到这个路由的?
具体的扫描过程是使用ScanUtil类,插入代码是RegisterCodeGenerator类。首先是拿到jar中LogisticsCenter.class文件的输入流,接着使用ASM自定义MyClassVisitor在visitMethod()方法中找到要插入代码的方法-loadRouterMap()。然后在自定义RouteMethodVisitor的visitInsn()方法中,确保在return之前插入代码。遍历所有帮助类,把帮助类路径中的"/“换成”." 。 LogisticsCenter 在loadRouterMap方法主动注册插件 会在此处插入代码。调用此方法就注册了全部的 Routers、Interceptors、Provider。

如何使用编译时生成的帮助类呢?
https://juejin.cn/post/7201879428086513720#heading-0
Gradle开发,APT采集页面路由信息:https://blog.csdn.net/weixin_46039528/article/details/132930598
https://blog.csdn.net/weixin_46039528/article/details/133105627
Gradle开发(三),字节码插桩,编译期间自动注册收集页面路由信息的映射表类并汇总:
https://blog.csdn.net/weixin_46039528/article/details/133366126
Android编译优化系列-kapt篇:https://juejin.cn/post/7070849501166059551

APT(Annotation Processing Tool),即 注解处理器,是javac中提供的编译时扫描和处理注解的工具,它对源代码文件进行检测找出其中的注解,然后使用注解进行额外的处理。
注解就像是一个标签,有很多类型,可以贴在某些元素上面进行标记,并且标签上可以写一些信息。APT就是用来处理标签的工具,在编译开始后,可以拿到自己所关心的类型的所有标签,然后根据标签信息和被标记的元素信息,做一些事情。做那些事呢,这就看你如何写APT了,你让他干啥他就干啥,通常都是会生成一些帮助类——帮助完成你的目的的类。 后面无论对这种标签的使用是增加、减少了,每次编译都会重新走这一过程,而上一次的处理结果会被清空。
宏观上理解,APT就是javac提供给开发者在编译时处理注解的一种技术;微观上,具体到实例中就是指 继承自javax.annotation.processing.AbstractProcessor 的实现类,即一个处理特定注解的处理器。(下文提到的APT都是宏观上理解,具体的处理器简称为Processor)
使用了APT,只要使用注解进行标记即可,无论使用者怎么标记,每次编译时都由APT统一处理,不会出错、也不担心有遗漏。
APT还有两个特点:
1、获取注解及生成代码都是在代码编译时候完成的,相比反射在运行时处理注解大大提高了程序性能。
2、注意APT并不能对源文件进行修改,只能获取注解信息和被注解对象的信息,然后做一些自定义的处理,例如生成java类。
在这里插入图片描述
在Java源码到class文件之间,需要经过注解处理器的处理,注解处理器生成的代码也同样会经过这一过程,最终一起生成class文件。在Android中,class文件还会被打进Dex文件中,最后生成APK文件。
在编译流程进入Processor前,APT会对整个Java源文件进行扫描,这样就会获取到 所有添加了的注解和对应被注解的类。 注解和被注解的类,一起被视为一个元素,即TypeElement,就是process()方法参数annotations的数据类型。 通过TypeElement,我们可以获取注解的所有信息、被注解类的所有信息,这样就可以根据这些信息来生成 我们需要的帮助类了。
最重要的就是 process()方法的实现:拿到所有关注的注解元素后,就是每个Processor的独自的逻辑——解析注解并生成需要的java文件。

Java文件要如何生成呢?这里就要介绍 javepoet 这个库了,通常APT框架中生成Java类都是使用javepoet。这里也不展开介绍,下面结合我添加的注释即可理解。

Gradle:一个自动化构建框架;在Android开发中,用来编译打包输出apk,还可以用来添加三方依赖。
Apk打包流程包括很多环节:源码文件经过JavaCompiler转为class文件、class经过dex操作变为dex文件、dex和资源等打包成apk、签名 等等一系列步骤,这就需要Google使用Gradle把这些操作都串联起来。

https://juejin.cn/post/7129157665732689934

LeakCanary

为弱引用指定一个引用队列,当弱引用指向的对象被回收时,此弱引用就会被添加到这个队列中,我们可以通过判断这个队列中有没有这个弱引用,来判断该弱引用指向的对象是否被回收了。
精简流程如下所示:
1、LeakCanary.install(application);此时使用application进行
2、registerActivityLifecycleCallbacks,从而来监听Activity的何时被destroy。
3、在onActivityDestroyed(Activity activity)的回调中,去检测Activity是否被回收,检测方式如以下步骤:
使用一个弱引用WeakReference指向这个activity,并且给这个弱引用指定一个引用队列queue,同时创建一个key来标识该activity。
然后将检测的方法ensureGone()投递到空闲消息队列。
当空闲消息执行的时候,去检测queue里面是否存在刚刚的弱引用,如果存在,则说明此activity已经被回收,就移除对应的key,没有内存泄漏发生。
如果queue里不存在刚刚的弱引用,则手动进行一次gc。
gc之后再次检测queue里面是否存在刚刚的弱引用,如果不存在,则说明此activity还没有被回收,此时已经发生了内存泄漏,直接dump堆栈信息并打印日志,否则没有发生内存泄漏,流程结束。

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

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

相关文章

tomcat与servlet

目录 一、Http服务器 二、tomcat 1、概念 2、tomcat解压缩文件 &#xff08;1&#xff09;bin文件夹 &#xff08;2&#xff09;conf文件夹 &#xff08;3&#xff09;logs &#xff08;4&#xff09;webapps 3、借助tomcat服务器访问网页 三、servlet 1、概念 2、s…

在微信公众号上怎么做报名链接_让你的活动报名与众不同

微信公众号报名链接&#xff1a;引领潮流&#xff0c;让你的活动报名与众不同 在这个信息爆炸的时代&#xff0c;微信早已成为我们生活中不可或缺的一部分。而微信公众号&#xff0c;更是成为了企业和个人传递信息、推广品牌的重要平台。如何在众多的微信公众号中脱颖而出&…

流量控制与熔断利器:Sentinel介绍

这是《百图解码支付系统设计与实现》专栏系列文章中的第&#xff08;19&#xff09;篇&#xff0c;也是流量控制系列的第&#xff08;6&#xff09;篇。点击上方关注&#xff0c;深入了解支付系统的方方面面。 本篇聊聊流量控制与熔断利器Sentinel&#xff0c;背后的原理&…

CVE-2024-0195 利用分析

1. 漏洞介绍 SpiderFlow爬虫平台项目中spider-flow-web\src\main\java\org\spiderflow\controller\FunctionController.java文件的FunctionService.saveFunction函数调用了saveFunction函数&#xff0c;该调用了自定义函数validScript&#xff0c;该函数中用户能够控制 functi…

系统架构设计师

软考系统架构设计师笔记 专用的成电路&#xff08;Application Specific Integrated Circuit&#xff0c;ASIC) PTR记录&#xff1a;Pointer Record&#xff0c;常被用于反向地址解析&#xff0c;即通过IP地址查询服务器域名。 软件工程 软件开发模型 【增量模型的优点】 …

大模型 RAG 面试篇

1.LLMs 存在模型幻觉问题&#xff0c;请问如何处理&#xff1f; 检索LLM。 先用问题在领域数据库里检索到候选答案&#xff0c;再用LLM对答案进行加工。 2.基于LLM向量库的文档对话 思路是怎么样&#xff1f; 加载文件读取文本文本分割文本向量化问句向量化在文本向量中匹配…

配置中心原理和选型

为什么需要配置中心&#xff1f; 缺乏整体管理&#xff0c;是配置管理变得低效 处于运维管理的需求 很容易导致实例的配置出现不一致的地方 生产环境多个集群直接修改配置&#xff0c;导致不一致 配置和代码在一起&#xff0c;配置修改需要重新发布&#xff0c;非常低效 目的是…

【C语言】编译和链接深度剖析

文章目录 &#x1f4dd;前言&#x1f320; 翻译环境和运行环境&#x1f309;翻译环境 &#x1f320;预处理&#xff08;预编译&#xff09;&#x1f309;编译 &#x1f320;词法分析&#x1f320;语法分析 &#x1f309;语义分析&#x1f320;汇编 &#x1f309; 链接&#x1f…

【教程】集群搭建准备工作全流程

基于VMware创建虚拟机进行集群搭建&#xff0c;适用于hadoop/GreenPlum等集群 之前已经创建了三台虚拟机hadoop102&#xff0c;hadoop103&#xff0c;hadoop104来搭建hadoop集群&#xff0c;因为目前学习到了greemplum&#xff0c;因此新建三台虚拟机hadoop105&#xff0c;had…

springboot110作业管理系统

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的作业管理系统 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资…

vue.js安装

1:下载 Node.js 官网&#xff1a;https://nodejs.org/en/download 2:安装 node -v npm -v 3:配置 npm config set prefix "F:\node\node_global" npm config set cache "F:\node\node_cache" 按 win 键并输入“编辑系统环境变量”调出系统属性界面&a…

AWTK 开源串口屏开发(7) - 屏幕保护

现代屏幕其实并不需要屏幕保护&#xff0c;不过屏幕保护程序会衍生一些其它用途。比如&#xff1a; 保护隐私。长时间不操作&#xff0c;通过动画或者其它方式隐藏屏幕内容。数据安全。长时间不操作&#xff0c;需要输入密码才能恢复。美观/广告。长时间不操作&#xff0c;显示…

C++中的static(静态)

2014年1月19日 内容整理自The Cherno:C系列 2014年1月20日 内容整理自《程序设计教程&#xff1a;用C语言编程 第三版》 陈家骏 郑滔 -----------------------------------------------------------------------------------------------------------------------------…

JS执行顺序

众所周知&#xff0c;JavaScript 是单线程语言,只能同时执行做一件事(js只有一个线程&#xff0c;称之为main thread-主线程) 1.Javascript 运行机制 main thread 主线程和 call-stack 调用栈(执行栈)&#xff0c;所有的任务都会被放到调用栈等待主线程执行。 2.Javascript 任…

SpringBoot+beetl idea热更新解决方案

SpringBootbeetl idea热更新解决方案 第一在application中开启&#xff1a; beetl:resource-auto-check: true #热加载beetl模板&#xff0c;开发时候用第二在application中开启&#xff1a; devtools: 这个部分专门用于配置Spring Boot DevTools的相关参数。DevTools…

十八周周报

文章目录 摘要文献阅读3D reconstruction of human bodies from single-view and multi-view images: A systematic review简介研究方法搜索策略选择标准搜索结果 三维重建方法单个视图中使用的技术基于参数化人体模型的回归基于非参数人体模型的回归 多个视图中使用的技术基于…

PaddleNLP评论观点抽取和属性级情感分析

项目地址&#xff1a;PaddleNLP评论观点抽取和属性级情感分析 - 飞桨AI Studio星河社区 (baidu.com) 情感分析旨在对带有情感色彩的主观性文本进行分析、处理、归纳和推理&#xff0c;其广泛应用于消费决策、舆情分析、个性化推荐等领域&#xff0c;具有很高的商业价值。 依托…

C#,因数分解(质因子分解)Pollard‘s Rho算法的源代码

因数分解&#xff08;也称为质因子分解&#xff09;&#xff1a;将一个大整数分解它的质因子之乘积的算法。 Pollard Rho算法的基本思路&#xff1a;先判断当前数是否是素数&#xff08;质数&#xff09;&#xff0c;如果是&#xff0c;则直接返回。如果不是&#xff0c;继续找…

11、Kafka ------ Kafka 核心API 及 生产者API 讲解

目录 Kafka核心API 及 生产者API讲解★ Kafka的核心APIKafka包含如下5类核心API&#xff1a; ★ 生产者APIKafka 的API 文档 ★ 使用生产者API发送消息 Kafka核心API 及 生产者API讲解 官方文档 ★ Kafka的核心API Kafka包含如下5类核心API&#xff1a; Producer API&#x…

spring data mongo 在事务中,无法自动创建collection

spring data mongo 在事务中,无法自动创建collection org.springframework.dao.DataIntegrityViolationException: Write operation error on server xxx:30001. Write error: WriteError{code=263, message=Cannot create namespace xxx.xxxin multi-document transaction.…