MVPArms官方快速组件化方案开源,来自5K star的信赖,程序员必学之一

ArmsComponent 组件化架构图

2.2 架构图详解

目前架构一共分为三层, 从低到高依次是基础层, 业务层和宿主层, 由于目前项目较小人员较少所以三层都集中在一个工程中, 但您可以根据项目的规模和开发人员的数量拆分成多个工程协同开发

2.2.1 宿主层

宿主层位于最上层, 主要作用是作为一个 App 壳, 将需要的模块组装成一个完整的 App, 这一层可以管理整个 App 的生命周期(比如 Application 的初始化和各种组件以及三方库的初始化)

2.2.2 业务层

业务层位于中层, 里面主要是根据业务需求和应用场景拆分过后的业务模块, 每个模块之间互不依赖, 但又可以相互交互, 比如一个商城 App搜索, 订单, 购物车, 支付 等业务模块组成

Tips: 每个业务模块都可以拥有自己独有的 SDK 依赖和自己独有的 UI 资源 (如果是其他业务模块都可以通用的 SDK 依赖 和 UI 资源 就可以将它们抽离到 基础 SDK(CommonSDK 2.2.3.3) 和 UI 组件(CommonRes 2.2.3.3.2) 中)

2.2.2.1 业务模块的拆分

写业务之前先不要急着动手敲码, 应该先根据初期的产品需求到后期的运营规划结合起来清晰的梳理一下业务在未来可能会发生的发展, 确定业务之间的边界, 以及可能会发生的变化, 最后再确定下来真正需要拆分出来的业务模块再进行拆分

2.2.3 基础层

基础层位于最底层, 里面又包括 核心基础业务模块公共服务模块基础 SDK 模块, 核心基础业务模块公共服务模块 主要为业务层的每个模块服务, 基础 SDK 模块 含有各种功能强大的团队自行封装的 SDK 以及第三方 SDK, 为整个平台的基础设施建设提供动力

2.2.3.1 核心基础业务

核心基础业务业务层 的每个业务模块提供一些与业务有关的基础服务, 比如在项目中以用户角色分为 2 个端口, 用户可以扮演多个角色, 但是在线上只能同时操作一个端口的业务, 这时每个端口都必须提供一个角色切换的功能, 以供用户随时在多个角色中切换, 这时在项目中就需要提供一个用于用户自由切换角色的管理类作为 核心基础业务 被这 2 个端口所依赖(类似 拉勾, Boss 直聘等 App 可以在招聘者和应聘者之间切换)

核心基础业务 的划分应该遵循是否为业务层大部分模块都需要的基础业务, 以及一些需要在各个业务模块之间交互的业务, 都可以划分为 核心基础业务

2.2.3.2 公共服务

公共服务 是一个名为 CommonServiceModule, 主要的作用是用于 业务层 各个模块之间的交互(自定义方法和类的调用), 包含自定义 Service 接口, 和可用于跨模块传递的自定义类

主要流程是:

提供服务的业务模块:

在公共服务(CommonService) 中声明 Service 接口 (含有需要被调用的自定义方法), 然后在自己的模块中实现这个 Service 接口, 再通过 ARouter API 暴露实现类

使用服务的业务模块:

通过 ARouterAPI 拿到这个 Service 接口(多态持有, 实际持有实现类), 即可调用 Service 接口中声明的自定义方法, 这样就可以达到模块之间的交互

跨模块传递的自定义类:

公共服务 中定义需要跨模块传递的自定义类后 (Service 中的自定义方法和 EventBus 中的事件实体类都可能需要用到自定义类), 就可以通过 ARouter API, 在各个模块的页面之间跨模块传递这个自定义对象 (ARouter 要求在 URL 中使用 Json 参数传递自定义对象必须实现 SerializationService 接口)

Tips: 建议在 CommonService 中给每个需要提供服务的业务模块都建立一个单独的包, 然后在这个包下放 Service 接口 和 需要跨模块传递的自定义类, 这样更好管理

掌握公共服务层的用法最好要了解 ARouter 的 API

点击查阅 ARouter 文档

2.2.3.3 基础 SDK

基础 SDK 是一个名为 CommonSDKModule, 其中包含了大量功能强大的 SDK, 提供给整个架构中的所有模块

2.2.3.3.1 MVPArms

MVPArms 是整个基础层中最重要的模块, 可谓是整个组件化架构中的心脏, 里面提供了开发一个完整项目所必须的一整套 APISDK, 是整个项目的脚手架, 我用它来统一整个组件化方案的基础设施, 使每一个模块更加健壮, 因为有了 MVPArms, 使得 ArmsComponent 成为了唯一提供完整基础框架的组件化方案, 所以学习 ArmsComponent 之前必须先学会 MVPArms

学习 MVPArms 时请按以下排列顺序依次学习:

1.点击学习 Demo

2.点击查阅 详细文档

3.点击下载 一键生成代码插件

2.2.3.3.2 UI 组件

基础 SDK 中的 UI 组件 是一个名为 CommonResModule, 主要放置一些业务层可以通用的与 UI 有关的资源供所有业务层模块使用, 便于重用、管理和规范已有的资源

Tips: 值得注意的是, 业务层的某些模块如果出现有资源名命名相同的情况 (如两个图片命名相同), 当在宿主层集成所有模块时就会出现资源冲突的问题, 这时注意在每个模块的 build.gradle 中使用 resourcePrefix 标签给每个模块下的资源名统一加上不同的前缀即可解决此类问题

android {
defaultConfig {
minSdkVersion rootProject.ext.android[“minSdkVersion”]

}
resourcePrefix “public_”
}

可以放置的资源类型有:

  • 通用的 Style, Theme
  • 通用的 Layout
  • 通用的 Color, Dimen, String
  • 通用的 Shape, Selector, Interpolator
  • 通用的 图片资源
  • 通用的 动画资源
  • 通用的 自定义 View
  • 通用的第三方 自定义 View

2.2.3.3.3 其他 SDK

其他 SDK 主要是 基础 SDK 依赖的一些业务层可以通用的 第三方库第三方 SDK (比如 ARouter, 腾讯 X5 内核), 便于重用、管理和规范已有的 SDK 依赖

2.3 跨组件通信

2.3.1 为什么需要跨组件通信?

因为各个业务模块之间是各自独立的, 并不会存在相互依赖的关系, 所以一个业务模块是访问不了其他业务模块的代码的, 如果想从 A 业务模块的 A 页面跳转到 B 业务模块的 B 页面, 光靠模块自身是不能实现的, 所以这时必须依靠外界的其他媒介提供这个跨组件通信的服务

2.3.2 跨组件通信场景

跨组件通信主要有以下两种场景:

  • 第一种是组件之间的页面跳转 (ActivityActivity, FragmentFragment, ActivityFragment, FragmentActivity) 以及跳转时的数据传递 (基础数据类型和可序列化的自定义类类型)

  • 第二种是组件之间的自定义类和自定义方法的调用(组件向外提供服务)

2.3.3 跨组件通信方案

其实以上两种通信场景甚至其他更高阶的功能在 ARouter 中都已经被实现, ARouterAlibaba 开源的一个 Android 路由中间件, 可以满足很多组件化的需求, 也是作为本方案中比较重要的一环, 需要认真看下文档, 了解下基本使用

关于跨组件通信框架, 本方案不做封装, 专业的事交给专业的人做, 此类优秀框架为数众多, 各有特点, 可以根据您的需求选择您喜欢的框架, 不一定非得是 ARouter, 选择 ARouter 也是因为 Alibaba 出品, 开源时间较长, 使用者众多, 相对稳定, 出现问题比较好沟通

2.3.4 跨组件通信方案分析

第一种组件之间的页面跳转不需要过多描述了, 算是 ARouter 中最基础的功能, API 也比较简单, 跳转时想传递不同类型的数据也提供有相应的 API (如果想通过在 URL 中使用 Json 参数传递自定义对象, 需要实现 SerializationService, 详情请查阅 ARouter 文档);

第二种组件之间的自定义类和自定义方法的调用要稍微复杂点, 需要 ARouter 配合架构中的 公共服务(CommonService) 实现, 主要流程在 公共服务(2.2.3.2) 中已有介绍, 这里我画了个示意图, 以便大家更好理解

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

跨组件通信示意图

此种服务提供方式叫作 接口下沉, 看图的同时请配合阅读 公共服务(2.2.3.2) 中的主要流程便于理解

本方案中还提供有 EventBus 来作为服务提供的另一种方式, 大家知道 EventBus 因为其解耦的特性, 如果被滥用的话会使项目调用层次结构混乱, 不便于维护和调试, 所以本方案使用 AndroidEventBus 其独有的 Tag, 可以在开发时更容易定位发送事件和接受事件的代码, 如果以组件名来作为 Tag 的前缀进行分组, 也可以更好的统一管理和查看每个组件的事件, 当然也不建议大家过多使用 EventBus

Tips: 每个跨组件通信框架提供服务的方式都不同, 您也可以选择其他框架的服务提供方式

2.3.5 跨组件传递复杂数据格式

在一般情况下基本数据类型就可以满足大多数跨组件传递数据的需求, 但是在某些情况下也会需要传递复杂的自定义数据类型, 传递自定义类型在方案中也提供有两种方式:

第一种在 公共服务(2.2.3.2) 中已提及, 就是在 公共服务 (CommonService) 中定义这个自定义类

第二种方式也比较简单, 直接通过解析 Json 字符串就可以传递

2.4 组件的生命周期

每个组件 (模块) 在测试阶段都可以独立运行, 在独立运行时每个组件都可以指定自己的 Application, 这时组件自己管理生命周期就轻而易举, 比如想在 onCreate 中初始化一些代码都可以轻松做到, 但是当进入集成调试阶段, 组件自己的 Application 已不可用, 每个组件都只能依赖于宿主的生命周期, 这时每个组件如果需要初始化自己独有的代码, 该怎么办?

2.4.1 问题分析

在集成调试阶段, 宿主依赖所有组件, 但是每个组件却不能依赖宿主, 意思是每个组件根本不知道自己的宿主是谁, 当然也就不能通过访问代码的方式直接调用宿主的方法, 从而在宿主的生命周期里加入自己的逻辑代码

如果直接将每个模块的初始化代码直接复制进宿主的生命周期里, 这样未免过于暴力, 不仅代码耦合不易扩展, 而且代码还极易冲突, 所以修改宿主源码的方式也不可行

所以有没有什么方法可以让每个组件在集成调试阶段都可以独自管理自己的生命周期呢?

其实解决思路很简单, 无非就是在开发时让每个组件可以独立管理自己的生命周期, 在运行时又可以让每个组件的生命周期与宿主的生命周期进行合并 (在不修改或增加宿主代码的情况下完成)

2.4.2 可行方案分析

想在不更改宿主代码的情况下在宿主的生命周期中动态插入每个组件的代码, 这倒有点像 AOP 的意思

现有的解决方案大概有三种:

  1. 在基础层中提供一个用于管理组件生命周期的管理类, 每个组件都手动将自己的生命周期实现类注册进这个管理类, 在集成调试时, 宿主在自己的 Application 对应生命周期方法中通过管理类去遍历调用注册的所有生命周期实现类即可

  2. 使用 AnnotationProcessor 解析注解在编译期间生成源代码自动注册所有组件的生命周期实现类, 然后宿主再在对应的生命周期方法中去调用

  3. 使用 Javassist 在编译时动态修改 class 文件, 直接在宿主的对应生命周期方法中插入每个组件的生命周期逻辑

我最后还是选择了第一种方法, 因为后面两种方法虽然使用简单, 还可以自动化的完成所有操作, 非常炫酷, 但是这两种方法技术实现复杂, 在不同的 Gradle 版本中还会出现兼容性问题影响整个项目的开发进度, 较难维护, 还会增加编译时间

选择第一种方法虽然增加了几步操作, 但是简单明了, 便与理解和维护, 后续人员加入也可以很快上手, 不受 Gradle 版本的影响, 也不会增加编译时间

2.4.3 最终执行方案

第一种方案具体原理也没什么好说的, 比较简单, 大概就是在基础层中定义有生命周期方法 (attachBaseContext(), onCreate() …) 的接口, 每个组件实现这个接口, 然后将实现类注册进基础层的管理器, 宿主通过管理器在对应的生命周期方法中调用所有的接口实现类, 典型的观察者模式, 类似注册点击事件

MVPArms 中这种方案的实现类叫作 ConfigModule, 每个组件都可以声明一个或多个 ConfigModule 实现类, 内部实现较为复杂, 实现原理是 反射 + 代理 + 观察者, 这个类也是整个 MVPArms 框架提供给开发者最重要的类

它可以给 MVPArms 框架配置大量的自定义参数, 包括项目中所有生命周期的管理 (Application, Activity, Fragment), 项目中所有网络请求的管理 (Retrofit, Okhttp, Glide),为框架提供了极大的扩展性, 使框架更加灵活

3 项目讲解

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

项目地址 : ArmsComponent

3.1 如何让组件独立运行?

在项目根目录的 gradle.properties 中, 改变 isBuildModule 的值即可

#isBuildModule 为 true 时可以使每个组件独立运行, false 则可以将所有组件集成到宿主 App 中
isBuildModule=true

3.2 配置 AndroidManifest

由于组件在独立运行时和集成到宿主时可能需要 AndroidManifest 配置不一样的参数, 比如组件在独立运行时需要其中的一个 Activity 配置了 <action android:name="android.intent.action.MAIN"/> 作为入口, 而当组件集成到宿主中时, 则依赖于宿主的入口, 所以不需要配置 <action android:name="android.intent.action.MAIN"/>, 这时我们就需要两个不同的 AndroidManifest 应对不同的情况

在组件的 build.gradle 中加入以下代码, 即可指定不同的 AndroidManifest, 具体请看项目代码

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

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

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

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

最后

总之啊,家里没矿的同学们,如果你们想以后的日子过得好一些,多想想你们的业余时间怎么安排吧;

技术方面的提升肯定是重中之重,但是技术外的一些“软实力”也不能完全忽视,很多时候升职确实是因为你的技术足够强,但也与你的“软实力”密切相关

在这我也分享一份大佬自己收录整理的 Android学习PDF+架构视频+面试文档+源码笔记 ,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这些都是我闲暇还会反复翻阅并给下属员工学习的精品资料。在脑图中,每个知识点专题都配有相对应的实战项目,可以有效的帮助大家掌握知识点。

总之也是在这里帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习

相信自己,没有做不到的,只有想不到的

+面试文档+源码笔记** ,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这些都是我闲暇还会反复翻阅并给下属员工学习的精品资料。在脑图中,每个知识点专题都配有相对应的实战项目,可以有效的帮助大家掌握知识点。

总之也是在这里帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习

[外链图片转存中…(img-GIKWaj9B-1711780965594)]

[外链图片转存中…(img-zn2MiADw-1711780965594)]

相信自己,没有做不到的,只有想不到的

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

  • 20
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值