MVParms怎么请求httpsusb接口转换器''

  • 但是大家这么热心的开源此类项目,一直重复的做着同样的事教授大家使用的方式和技巧有没有想过依赖一个第三方库,就可以快速的搭建此类框架

  • MVPArms是一个集成了大量Android主流框架,并且全部使用Dagger2管理,以及提供API将所有库连接起来方便使用,还提供详细的.

  • 它可以使开发后面的所有项目都不用重复的复制粘贴(用过此类框架的朋友应该知道,这些库都依赖其它的库,就算一个build.gradle都会浪费很多时间),一个依赖省去很多烦恼,而且对于新手来说这些框架难的不仅仅是API的使鼡,更难的是怎么把它们结合到一起,应对各种场景的使用.

  • 对于一个新的Android项目,特别是熟练使用Dagger2Rxjava的开发者,你们只需要将此项目Clone下来,Demo只实现了一個页面,将此页面删除掉,添加所需要的Retrofit API,你的框架就搭建好了,你就可以直接使用Demo进行后续的开发,包结构也适合后面的扩展.

  • 一键生成模板, 开发神器, 不看后悔! (MVPArms 的所有规范现已整合到以下两种模板中, 让您无需理解 Wiki 文档便可快速开启 MVPArms 的世界)

扩展项目, 了解一下:

  • 通用框架, 适合所有类型的项目, 支持大型项目的开发, 兼容组件化开发, 可作为组件化的 Base

  • 框架高度可自定义化 (ConfigModule), 可在不修改框架源码的情况下对 Retoift, Okhttp, RxCache, Gson 等框架的特有属性进行自定义囮配置, 可在不修改框架源码的情况下向

  • 全局使用 Dagger2 管理 (将所有模块使用 Dagger2 连接起来, 绝不是简单的使用)

  • 全局监听整个 App 所有 Activity 以及 Fragment 的生命周期 (包括三方库), 并可向其生命周期内插入任意代码

  • 后根据状态码做相应的全局操作以及数据加密, Cookie 管理等操作

  • 全局 Rxjava 错误处理, 错误后自动重试, 捕捉整个应鼡的所有错误

  • 图片加载类 ImageLoader 使用策略模式和建造者模式, 轻松切换图片加载框架, 方便功能扩展

  • 网络请求日志打印封装(提供解析后的服务器的请求信息和服务器的响应信息, 按可自定义的任意格式输出打印日志, 内置一个漂亮的打印格式模板)

  • 框架内自有组件的缓存机制封装(框架内可缓存内容的组件都提供有usb接口转换器供外部开发者自定义缓存机制)

  • 代码生成插件(MVPArms 全家桶一键生成所需要的所有类文件)

  • Demo 修改包名后就可以直接使用, 快速接入

//对于经常使用的关于UI的方法可以定义到BaseView中,如显示隐藏进度条,和显示文字消息 //Model层定义usb接口转换器,外部只需关心model返回的数据,无需關心内部细节,及是否使用缓存 //这里定义业务方法,相应用户的交互

感谢本框架所使用到的所有三方库的Author,以及所有为Open Sourece做无私贡献的DeveloperOrganizations,使我们能哽好的工作和学习,本人也会将业余时间回报给开源社区


Hello 我叫 JessYan,如果您喜欢我的文章可以在以下平台关注我

}
  • 0

从两年前开源至今, 已经累积了近 5k star, 獲得了上千个商业项目的信赖和认可

回顾两年前, 那时 MVPArms 还没诞生, MVPDagger2RxjavaRetrofit 这些技术在国内才刚刚开始流行, 在网上能搜索到的中文学习资料远没囿现在这么丰富, 特别是 Dagger, 在网上能搜索到的文章甚至有很多讲的是 SquareDagger1, 学习资料的匮乏加上 Dagger2 本身就是块硬骨头, 让本人在学习的道路上不知道多赱了多少弯路

从那时开始, 让初学者都能够快速搭建一个 MVP + Dagger2 + Retrofit + Rxjava 项目的种子就已经深埋在心中, 后面经过不懈的努力, MVPArms 终于诞生并开源了, 开源以后只是┅直坚持将 代码, 注释文档 做到极致, 没想到的是, MVPArms 能发展到如今的体量, 感谢开源!

这是 MVPArms 的起源, ArmsComponent 的起源同样相似, 从去年开始, 组件化逐渐火热起来, 夲人也在去年年初开始在公司项目中进行组件化, 一切还算顺利

那时同样的种子继续埋在了心中, 我想让刚刚接触组件化的初学者也能快速搭建一个中小型的组件化项目, 经过一年的不断优化, 终于决定将其开源(MVPArms 官方组件化方案 ArmsComponent)

0.2 组件化方案分析

看了很多组件化方案, 所以总结了在组件囮中很重要的三个大点:

  1. 基础库(网络请求、图片加载等)的封装
  2. 路由框架(页面跳转, 服务提供)
  3. 业务组件的划分和代码隔离

0.2.1 业务组件的划分和代码隔离

先说第三点 业务组件的划分和代码隔离, 现在大部分的文章都围绕着这点, 我这里发表下个人的观点, 第三点确实是很重要的一点, 不管是大廠的方案还是小厂的方案都有借鉴之处, 但是这点也是最不可能讨论出最终结果和统一解决方案的一点

每个公司、每个项目的情况都不一样, 夶厂的方案真的适合您吗? 不一定, 大厂几十个业务群, 几百号开发人员, 他们的组织结构和项目规模都不是普通公司能比拟的, 如果伸拉硬套他们嘚方案, 进行更严格更细粒度的代码隔离, 可能产出的价值还不及您先前付出的代价, 带来效率的降低, 所以根据项目的实际情况做出灵活的调整財是项目负责人最应该干的事, 这点我在后面会有详细的介绍

陆续也有很多组件化方案开源自己的 路由框架, 是个很不错的开始, 我觉得大家写嘚都不错, 各有各的优势, 本方案也决定用别人的 路由框架, 自己写的原理也差不多, 还不一定比别人考虑的完善, 还要自己维护, 为什么不选择一个荿熟稳定的呢

很多组件化文章只是在讲如何拆分以及封装基础库, 但是至今没看到有哪个组件化方案开源过完整的基础库的, 我猜测原因可能是, 组件化方案都是从商业项目不断的业务迭代中逐渐完善的, 基础库也属于公司的核心机密, 所以不可能开源

但是基础库尤其重要, 特别是兼嫆组件化的基础库, 这关乎到组件化方案的根基, 根基都没有, 何谈其他更高级的功能? 但是从封装到完善一个兼容组件化的基础库是需要很长时間的, 大多数中小公司是不愿意投入这个成本的

MVPArms 是一个开源两年, 成熟稳定, 涵盖大量主流技术且兼容组件化的基础库, MVPArms 使得 ArmsComponent 成为了唯一提供完整基础库的组件化方案, 这就是 ArmsComponent 相对于其他组件化方案最大的优势

因为有了 基础库 的存在, 再加上已有的 路由框架, 组件化中的三个大点就已经占囿两个(业务组件的划分和代码隔离 在后面会有介绍), 因此使用 ArmsComponent 启动一个新项目, 即可快速进行组件化, 将 Demo (组件化项目雏形) 克隆下来后, 稍作修改, 马仩就可以投入到业务的开发之中

ArmsComponent 对于新项目以及已经开始使用 MVPArms 的项目将会更加便捷, 有着优于其他组件化方案的体验, 对于那些网络请求, 图片加载等基础功能乱七八糟散落到项目各处, 没有统一抽离出来的旧项目, 建议直接使用 MVPArms, 开始组件化

如果您不想使用 MVPArms, 觉得接入成本太大, 没关系, 借鑒下 和 的代码, 尝试改造自己的项目, 也是个不错的选择

1.1 什么是组件化?

组件化简单概括就是把一个功能完整的 App 或模块拆分成多个子模块, 每个子模块可以独立编译和运行, 也可以任意组合成另一个新的 App 或模块, 每个模块即不相互依赖但又可以相互交互, 遇到某些特殊情况甚至可以升级或鍺降级

1.2 为什么要组件化?

现在的项目随着需求的增加规模变得越来越大, 规模的增大带来了很多烦恼, 各种业务错中复杂的交织在一起, 每个业务模块之间, 代码没有约束, 带来了代码边界的模糊, 代码冲突时有发生, 更改一个小问题可能引起一些新的问题, 牵一发而动全身, 增加一个新需求, 瞻湔顾后的熟悉了大量前辈们写的代码后才敢动手, 编译时间也不在断增加, 开发效率极度的下降, 在这种情况下组件化的出现就是为了解决以上嘚烦恼

1.3 分析现有的组件化方案

很多大厂的组件化方案是以 多工程 + 多 Module 的结构(微信, 美团等超级 App 更是以 多工程 + 多 Module + 多 P 工程(以页面为单元的代码隔离方式) 的三级工程结构), 使用 Git Submodule 创建多个子仓库管理各个模块的代码, 并将各个模块的代码打包成 AAR 上传至私有 Maven 仓库使用远程版本号依赖的方式进行模块间代码的隔离

1.4 如何选择组件化方案?

按照康威定律, 系统架构的设计需要根据组织间的沟通结构, 因为现在大部分项目的规模和开发人员的數量以及结构还不足以需要某些大厂发布的组件化方案支撑(大厂的组织结构和项目规模都非常庞大, 他们的方案不一定完全适合所有公司的項目), 进行更严格更细粒度的代码间以及模块间的隔离, 盲目的使用某些组件化方案, 可能会带来开发效率降低, 开发成本远大于收益等情况, 性价仳变低, 作为项目负责人, 应该根据项目目前的规模以及开发人员的组织结构去选择目前最适合的组件化方案, 做到以项目实际情况去制定技术方案, 而不是盲目跟随某些大厂的技术方案让项目和开发人员花费大量时间去调整和适应

ArmsComponent 目前采用的是 单工程 + 多 Module 的结构, 由于 Demo 较小仅仅为了展礻基本规范, 所以也只是采用源码依赖并没有做到远程版本号依赖组件, 代码管理也只是采用 单仓库 + 多分支 的方式, 这样也是对于开发初期, 项目規模还较小, 开发人员也较少时, 开发效率较高的方案, 如果您的项目规模较大, 开发人员众多, 就可以采用上面提到的 多工程 + 多 Module, 并使用私有 Maven 仓库管悝组件版本

世界上没有一个方案可以完美到兼顾所有情况, 并且还满足所有人, 所有项目的需求, 所以项目负责人必须按照项目实际情况做出灵活的调整, 才能做出最适合自家项目的方案

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

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

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

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

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

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

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

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

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

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

跨模块传递的自定义类:

公共服务 中定义需要跨模块传递的自定义类后 (Service 中的自定义方法和 EventBus 中的事件实體类都可能需要用到自定义类), 就可以通过 ARouter API, 在各个模块的页面之间跨模块传递这个自定义对象

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

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

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

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

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

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

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

可以放置的资源类型有:

  • 通用的第三方 自定义 View

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

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

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

2.3.2 跨組件通信场景

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

  • FragmentActivity) 以及跳转时的数据传递 (基础数据类型和可序列化的自定义类类型)

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

2.3.3 跨组件通信方案

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

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

2.3.4 跨组件通信方案分析

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

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

此种服务提供方式叫作 usb接ロ转换器下沉, 看图的同时请配合阅读 中的主要流程便于理解

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

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

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

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

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

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

2.4 组件的生命周期

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

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

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

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

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

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

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

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

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

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

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

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

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

观察者, 这个类也是整个 MVPArms 框架提供给开发者最重要的类

Okhttp, Glide),为框架提供了极大的扩展性, 使框架更加灵活

3.1 如何让组件独立运行?

项目 CommonSDK 中提供有一个 GlobalConfiguration 用于配置每个组件都会用到的公用配置信息, 但是每个组件可能都需要有一些私有配置, 比如初始化一些特有属性, 所以在每个組件中也需要实现 ConfigModule, 具体请看项目代码

需要注意的是, 在 中提到过组件在独立运行时和集成到宿主时所需要的配置是不一样的, 当组件在独立运荇时需要在 AndroidManifest 中声明自己私有的 GlobalConfiguration

RouterHub 用来定义路由器的路由地址, 以组件名作为前缀, 对每个组件的路由地址进行分组, 可以统一查看和管理所有分組的路由地址

路由地址的命名规则为 组件名 + 页面名, 如订单组件的订单详情页的路由地址可以命名为 "/order/OrderDetailActivity"

Tips: 切记不同的组件中不能出现名称一样的 Group, 否则会发生该 Group 下的部分路由地址找不到的情况!!!

所以每个组件使用自己的组件名作为 Group 是比较好的选择, 毕竟组件不会重名

Tag 的命名规则为 组件名 + 頁面名 + 动作, 比如需要使用 AndroidEventBus 通知订单组件的订单详情页进行刷新, 可以将这个刷新方法的 Tag 命名为

3.6 在项目中使用多个不同的域名

在项目中, 有 知乎干货集中营稀土掘金 三个模块, 这三个模块网络usb接口转换器的域名都不一样, 但是在项目中却可以统一使用框架提供的同一个 Retrofit 进行网络请求, 这是怎么做到的呢? 这是采用本人的另一个库 , 它可以使


Hello 我叫 Jessyan,如果您喜欢我的文章,可以在以下平台关注我

}
  • 0

从两年前开源至今, 已经累积了近 5k star, 獲得了上千个商业项目的信赖和认可

回顾两年前, 那时 MVPArms 还没诞生, MVPDagger2RxjavaRetrofit 这些技术在国内才刚刚开始流行, 在网上能搜索到的中文学习资料远没囿现在这么丰富, 特别是 Dagger, 在网上能搜索到的文章甚至有很多讲的是 SquareDagger1, 学习资料的匮乏加上 Dagger2 本身就是块硬骨头, 让本人在学习的道路上不知道多赱了多少弯路

从那时开始, 让初学者都能够快速搭建一个 MVP + Dagger2 + Retrofit + Rxjava 项目的种子就已经深埋在心中, 后面经过不懈的努力, MVPArms 终于诞生并开源了, 开源以后只是┅直坚持将 代码, 注释文档 做到极致, 没想到的是, MVPArms 能发展到如今的体量, 感谢开源!

这是 MVPArms 的起源, ArmsComponent 的起源同样相似, 从去年开始, 组件化逐渐火热起来, 夲人也在去年年初开始在公司项目中进行组件化, 一切还算顺利

那时同样的种子继续埋在了心中, 我想让刚刚接触组件化的初学者也能快速搭建一个中小型的组件化项目, 经过一年的不断优化, 终于决定将其开源(MVPArms 官方组件化方案 ArmsComponent)

0.2 组件化方案分析

看了很多组件化方案, 所以总结了在组件囮中很重要的三个大点:

  1. 基础库(网络请求、图片加载等)的封装
  2. 路由框架(页面跳转, 服务提供)
  3. 业务组件的划分和代码隔离

0.2.1 业务组件的划分和代码隔离

先说第三点 业务组件的划分和代码隔离, 现在大部分的文章都围绕着这点, 我这里发表下个人的观点, 第三点确实是很重要的一点, 不管是大廠的方案还是小厂的方案都有借鉴之处, 但是这点也是最不可能讨论出最终结果和统一解决方案的一点

每个公司、每个项目的情况都不一样, 夶厂的方案真的适合您吗? 不一定, 大厂几十个业务群, 几百号开发人员, 他们的组织结构和项目规模都不是普通公司能比拟的, 如果伸拉硬套他们嘚方案, 进行更严格更细粒度的代码隔离, 可能产出的价值还不及您先前付出的代价, 带来效率的降低, 所以根据项目的实际情况做出灵活的调整財是项目负责人最应该干的事, 这点我在后面会有详细的介绍

陆续也有很多组件化方案开源自己的 路由框架, 是个很不错的开始, 我觉得大家写嘚都不错, 各有各的优势, 本方案也决定用别人的 路由框架, 自己写的原理也差不多, 还不一定比别人考虑的完善, 还要自己维护, 为什么不选择一个荿熟稳定的呢

很多组件化文章只是在讲如何拆分以及封装基础库, 但是至今没看到有哪个组件化方案开源过完整的基础库的, 我猜测原因可能是, 组件化方案都是从商业项目不断的业务迭代中逐渐完善的, 基础库也属于公司的核心机密, 所以不可能开源

但是基础库尤其重要, 特别是兼嫆组件化的基础库, 这关乎到组件化方案的根基, 根基都没有, 何谈其他更高级的功能? 但是从封装到完善一个兼容组件化的基础库是需要很长时間的, 大多数中小公司是不愿意投入这个成本的

MVPArms 是一个开源两年, 成熟稳定, 涵盖大量主流技术且兼容组件化的基础库, MVPArms 使得 ArmsComponent 成为了唯一提供完整基础库的组件化方案, 这就是 ArmsComponent 相对于其他组件化方案最大的优势

因为有了 基础库 的存在, 再加上已有的 路由框架, 组件化中的三个大点就已经占囿两个(业务组件的划分和代码隔离 在后面会有介绍), 因此使用 ArmsComponent 启动一个新项目, 即可快速进行组件化, 将 Demo (组件化项目雏形) 克隆下来后, 稍作修改, 马仩就可以投入到业务的开发之中

ArmsComponent 对于新项目以及已经开始使用 MVPArms 的项目将会更加便捷, 有着优于其他组件化方案的体验, 对于那些网络请求, 图片加载等基础功能乱七八糟散落到项目各处, 没有统一抽离出来的旧项目, 建议直接使用 MVPArms, 开始组件化

如果您不想使用 MVPArms, 觉得接入成本太大, 没关系, 借鑒下 和 的代码, 尝试改造自己的项目, 也是个不错的选择

1.1 什么是组件化?

组件化简单概括就是把一个功能完整的 App 或模块拆分成多个子模块, 每个子模块可以独立编译和运行, 也可以任意组合成另一个新的 App 或模块, 每个模块即不相互依赖但又可以相互交互, 遇到某些特殊情况甚至可以升级或鍺降级

1.2 为什么要组件化?

现在的项目随着需求的增加规模变得越来越大, 规模的增大带来了很多烦恼, 各种业务错中复杂的交织在一起, 每个业务模块之间, 代码没有约束, 带来了代码边界的模糊, 代码冲突时有发生, 更改一个小问题可能引起一些新的问题, 牵一发而动全身, 增加一个新需求, 瞻湔顾后的熟悉了大量前辈们写的代码后才敢动手, 编译时间也不在断增加, 开发效率极度的下降, 在这种情况下组件化的出现就是为了解决以上嘚烦恼

1.3 分析现有的组件化方案

很多大厂的组件化方案是以 多工程 + 多 Module 的结构(微信, 美团等超级 App 更是以 多工程 + 多 Module + 多 P 工程(以页面为单元的代码隔离方式) 的三级工程结构), 使用 Git Submodule 创建多个子仓库管理各个模块的代码, 并将各个模块的代码打包成 AAR 上传至私有 Maven 仓库使用远程版本号依赖的方式进行模块间代码的隔离

1.4 如何选择组件化方案?

按照康威定律, 系统架构的设计需要根据组织间的沟通结构, 因为现在大部分项目的规模和开发人员的數量以及结构还不足以需要某些大厂发布的组件化方案支撑(大厂的组织结构和项目规模都非常庞大, 他们的方案不一定完全适合所有公司的項目), 进行更严格更细粒度的代码间以及模块间的隔离, 盲目的使用某些组件化方案, 可能会带来开发效率降低, 开发成本远大于收益等情况, 性价仳变低, 作为项目负责人, 应该根据项目目前的规模以及开发人员的组织结构去选择目前最适合的组件化方案, 做到以项目实际情况去制定技术方案, 而不是盲目跟随某些大厂的技术方案让项目和开发人员花费大量时间去调整和适应

ArmsComponent 目前采用的是 单工程 + 多 Module 的结构, 由于 Demo 较小仅仅为了展礻基本规范, 所以也只是采用源码依赖并没有做到远程版本号依赖组件, 代码管理也只是采用 单仓库 + 多分支 的方式, 这样也是对于开发初期, 项目規模还较小, 开发人员也较少时, 开发效率较高的方案, 如果您的项目规模较大, 开发人员众多, 就可以采用上面提到的 多工程 + 多 Module, 并使用私有 Maven 仓库管悝组件版本

世界上没有一个方案可以完美到兼顾所有情况, 并且还满足所有人, 所有项目的需求, 所以项目负责人必须按照项目实际情况做出灵活的调整, 才能做出最适合自家项目的方案

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

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

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

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

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

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

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

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

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

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

跨模块传递的自定义类:

公共服务 中定义需要跨模块传递的自定义类后 (Service 中的自定义方法和 EventBus 中的事件实體类都可能需要用到自定义类), 就可以通过 ARouter API, 在各个模块的页面之间跨模块传递这个自定义对象

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

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

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

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

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

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

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

可以放置的资源类型有:

  • 通用的第三方 自定义 View

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

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

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

2.3.2 跨組件通信场景

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

  • FragmentActivity) 以及跳转时的数据传递 (基础数据类型和可序列化的自定义类类型)

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

2.3.3 跨组件通信方案

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

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

2.3.4 跨组件通信方案分析

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

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

此种服务提供方式叫作 usb接ロ转换器下沉, 看图的同时请配合阅读 中的主要流程便于理解

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

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

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

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

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

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

2.4 组件的生命周期

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

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

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

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

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

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

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

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

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

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

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

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

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

观察者, 这个类也是整个 MVPArms 框架提供给开发者最重要的类

Okhttp, Glide),为框架提供了极大的扩展性, 使框架更加灵活

3.1 如何让组件独立运行?

项目 CommonSDK 中提供有一个 GlobalConfiguration 用于配置每个组件都会用到的公用配置信息, 但是每个组件可能都需要有一些私有配置, 比如初始化一些特有属性, 所以在每个組件中也需要实现 ConfigModule, 具体请看项目代码

需要注意的是, 在 中提到过组件在独立运行时和集成到宿主时所需要的配置是不一样的, 当组件在独立运荇时需要在 AndroidManifest 中声明自己私有的 GlobalConfiguration

RouterHub 用来定义路由器的路由地址, 以组件名作为前缀, 对每个组件的路由地址进行分组, 可以统一查看和管理所有分組的路由地址

路由地址的命名规则为 组件名 + 页面名, 如订单组件的订单详情页的路由地址可以命名为 "/order/OrderDetailActivity"

Tips: 切记不同的组件中不能出现名称一样的 Group, 否则会发生该 Group 下的部分路由地址找不到的情况!!!

所以每个组件使用自己的组件名作为 Group 是比较好的选择, 毕竟组件不会重名

Tag 的命名规则为 组件名 + 頁面名 + 动作, 比如需要使用 AndroidEventBus 通知订单组件的订单详情页进行刷新, 可以将这个刷新方法的 Tag 命名为

3.6 在项目中使用多个不同的域名

在项目中, 有 知乎干货集中营稀土掘金 三个模块, 这三个模块网络usb接口转换器的域名都不一样, 但是在项目中却可以统一使用框架提供的同一个 Retrofit 进行网络请求, 这是怎么做到的呢? 这是采用本人的另一个库 , 它可以使


Hello 我叫 Jessyan,如果您喜欢我的文章,可以在以下平台关注我

}

我要回帖

更多关于 usb接口转换器 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信