企业级项目组件化重构之路

前言

在之前的文章中,我们讲解了云音乐应用的基本库构建。今天,我们将进行一场 组件化代码重构

基于组件的库包系列文章 如下:

Android组件开发(一)——Maven私服构建

Android组件开发(二)——网络请求组件封装

Android组件开发(三)——图片加载组件封装

Android组件开发(四)——Process Keep-Alive组件的封装

Android组件开发(五)——音乐播放组件完整版打包

Android组件开发(六)——短视频播放组件封装

Android组件开发(七)——教你分析项目需求,从零开始实现

项目地址 github.com/ByteYuhb/an…

项目演示

090223022232_0device-2022-09-02-225448.png

1. 组件化重构效果

下面是我们重建前后的框架图对比:

重构前:

传统代码架构.png

重构后

组件化代码架构.png

  • ft_xxx 代表业务层模块 lib_xxx 表示一个基础库模块

重构后的架构图如下

服务接口调用.png

重构前的代码业务被封装在宿主应用程序中,业务耦合严重。如果修改了一个业务模块,就需要对整个app进行完整的测试,测试工作量巨大。
重构之后,我们只需要独立调试一个应用。

重构框架结构: 所有业务组件都通过 **ft_base_service** 交流

2. 组件化重构指南

    1. 单个业务可以单独调试,也可以作为lib提供给宿主应用
    1. 不允许直接调用同级的模块。比如我们的ft_home组件是不允许直接调用ft_login组件的,否则就不存在组件化的意义了。
    1. 组件之间的通信不能通过显示的类文件直接跳转。可以考虑使用 ARouter 框架进行解耦。
    1. 每个组件都可以打包成aar或者jar,上传到maven私服。宿主机使用时,可以直接引用私服中的aar包。

如果你能做到以上几点,你的应用就可以称为组件化框架应用。

3.组件化重构思路

重构思路.png

    1. 拆除 : 拆迁代码、拆迁资源、拆迁施工
      由于所有业务和资源都耦合在宿主应用程序中,因此需要将代码和资源分离到相应的模块中
      当然我们的build.gradle也需要拆分成不同的模块
    1. 抓住 : 提供外部接口
      组件之间没有直接的通信,需要通过暴露的接口进行外部通信。
    1. 测量 : 重复测试
      重构后代码需要反复测试,防止出现意外bug

4. 组件化重构过程

我在这里登录业务 ft_login 例如:

1. 步骤1 : 首先新建一个业务模块 ft_login ,然后在宿主应用程序中提取与登录功能相关的代码和资源 ft_login 中间

2. 第2步 :将与登录构建相关的依赖项分配给 ft_login 正在建设中。

3. 第 3 步 : 单独调试功能的实现

  • 3.1:在 gradle.properties 在以下位置创建一个全局变量: isRunAlone=真

  • 3.2:在 构建.gradle 中间:

    if(isRunAlone.toBoolean()){
    应用插件:'com.android.application'
    } 别的{
    应用插件:'com.android.library'
    }

    安卓 {
    compileSdkVersion 33
    构建工具版本“33.0.0”

    默认配置 {
    if(isRunAlone.toBoolean()){
    applicationId 'com.anna.ft_login'
    }
    ...
    }
    源集{
    主要的 {
    爪哇{
    srcDirs = ['src/main/java']
    }
    资源 {
    srcDirs = ['src/main/res']
    }
    添加{
    srcDirs = ['src/main/aidl']
    }
    显现 {
    if(isRunAlone.toBoolean()){
    srcFile 'src/main/manifest/AndroidManifest.xml'
    } 别的 {
    srcFile 'src/main/AndroidManifest.xml'
    }
    }
    }
    }
    }
    def 依赖列表 = [rootProject.depsLibs.okhttp,
    rootProject.depsLibs.gson,
    rootProject.depsLibs.appcompact,
    rootProject.depsLibs.design,
    rootProject.depsLibs.eventbus,
    rootProject.depsLibs.arouterapi,
    ':lib_network', ':lib_common_ui', ':ft_base_service']

    依赖{
    if(!isRunAlone.toBoolean()){
    依赖列表.each { 字符串依赖 ->
    依赖.startsWithAny(':lib', ':ft')? compileOnly(project(depend)):compileOnly(depend){
    开关(依赖){
    案例 rootProject.depsLibs.arouterapi:
    排除组:'com.android.support'
    休息;
    }
    }
    }
    } 别的 {
    依赖列表.each { 字符串依赖 ->
    依赖.startsWithAny(':lib', ':ft')?实施(项目(依赖)):实施(依赖){
    开关(依赖){
    案例 rootProject.depsLibs.arouterapi:
    排除组:'com.android.support'
    休息;
    }
    }
    }
    }
    //路由注解处理器
    annotationProcessor rootProject.depsLibs.aroutercompiler

    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

    }

    复制代码

个别调试状态注意四点

  • 1.参考应用插件
  • 2.引入applicationId
  • 3. 为sourceSets引入不同的构建路径
  • 4.导入的库需要单独调试状态下使用 执行 导入,不能使用 只编译

实现以上四点, 只需打开 isRunAlone 即可作为单独的应用程序运行 .

4. 第四步:组件之间的通信

在这里,我们介绍一个 ft_base_service 模块,该模块用于实现组件之间的通信,需要调用其他业务模块才能使用该模块进行通信,
业务模块和 ft_base_service 通讯使用 路由 ARouter
关于 路由器 使用可以参考这篇文章:

Android开源系列——组件化框架Arouter——(一)使用详解

  • 1. 创建 ft_base_service ,在这个模块中:创建一个 登录服务 接口继承 提供者

引入 ARouter 依赖

 安卓 {  
 javaCompileOptions {  
 注释处理器选项 {  
 参数 = [AROUTER_MODULE_NAME:project.getName(),AROUTER_GENERATE_DOC:“启用”]  
 }  
 }  
 }  
 //路由核心api  
 实现 rootProject.depsLibs.arouterapi  
 //路由注解处理器  
 annotationProcessor rootProject.depsLibs.aroutercompiler  
 复制代码

创建登录服务:

 公共接口 LoginService 扩展 IProvider {  
 boolean hasLogin();  
 无效登录(上下文上下文);  
 }  
 复制代码
  • 2. 在 ft_login 在业务模块中实现LoginService接口

注意,因为这里使用了 ARouter 注解,所以也需要引入 路由器 依靠

 @Route(path = "/login/login_service")  
 公共类 LoginServiceImpl 实现 LoginService {  
 上下文上下文;  
 @覆盖  
 公共布尔 hasLogin () {  
 返回 UserManager.getInstance().hasLogined();  
 }  
  
 @覆盖  
 公共无效登录(上下文上下文){  
 LoginActivity.start(context);  
 }  
  
 @覆盖  
 公共无效初始化(上下文上下文){  
 Log.d("TAG", "LoginServiceImpl is init");  
 }  
 }  
 复制代码
  • 3. 在 ft_base_service 模块对 登录服务 依赖注入接口

    公共类 LoginImpl {

    @Autowired(name = "/login/login_service")
    公共登录服务 mLoginService;
    私有静态 LoginImpl mLoginImpl = null;
    公共静态 LoginImpl getInstance () {
    if (mLoginImpl == null) {
    同步(LoginImpl.class){
    if (mLoginImpl == null) {
    mLoginImpl = new LoginImpl();
    }
    返回 mLoginImpl;
    }
    }
    返回 mLoginImpl;
    }

    私人登录Impl(){
    ARouter.getInstance().inject(this);
    }
    公共布尔 hasLogin (){
    返回 mLoginService.hasLogin();
    }
    公共无效登录(上下文上下文){
    mLoginService.login(上下文);
    }

    }
    复制代码

作者使用了一个 单例类 LoginImpl , 在构造函数中 登录服务 依赖注入

ARouter.getInstance().inject(this);

那么宿主app或者其他模块在引用登录业务功能时,需要依赖 **ft_base_service** 模块,并使用 **LoginImpl** 接口可以使用。

这里解释一下,我们通常使用 四分量跳跃 也可以用这个方法来处理,只需要在服务接口中定义跳转接口即可。当然也可以使用Arouter的Activity跳转方式或者Fragment实例获取方式。

  • 5.代码打包aar上传到 maven私人服务器

更多关于这个maven私服的信息,请参考这篇文章:

Gradle 基础(六)——使用 Maven 发布组件化类库

这里我们封装了一个通用的组件发布库:

 应用插件:'maven'  
  
  
 上传档案{  
 存储库{  
 mavenDeployer {  
 // 是否快照版本  
 def isSnapShot = Boolean.valueOf(MAVEN_IS_SNAPSHOT)  
 def versionName = MAVEN_VERSION  
 if (isSnapShot) {  
 版本名称 += "-SNAPSHOT"  
 }  
 // 组件信息  
 pom.groupId = MAVEN_GROUP_ID  
 pom.artifactId = MAVEN_ARTIFACTID  
 pom.version = 版本名称  
  
 // 快照存储库路径  
 快照存储库(网址:uri(MAVEN_SNAPSHOT_URL)){  
 身份验证(用户名:MAVEN_USERNAME,密码:MAVEN_USERNAME)  
 }  
 // 发布仓库路径  
 存储库(网址:uri(MAVEN_RELEASE_URL)){  
 身份验证(用户名:MAVEN_USERNAME,密码:MAVEN_USERNAME)  
 }  
  
 println("#####################################"  
 + "\nuploadArchives = " + pom.groupId + ":" + pom.artifactId + ":" + pom.version + "." + pom.包装  
 + "\nrepository=" + (isSnapShot ? MAVEN_SNAPSHOT_URL : MAVEN_RELEASE_URL)  
 + "\n####################################"  
 )  
 }  
 }  
 }  
  
 复制代码

然后在对应的组件下面引用它:

 申请自:文件('../maven.gradle')  
 复制代码

直接在发布时 摇篮 在面板中单击 上传档案 任务

task面板.png

经过以上步骤,基本完成了登录组件的打包和发布,对外提供了登录组件接口。
其他组件也按照上述逻辑进行重构

更多详情可自行获取 项目源代码 查看。

5.组件化重构总结

组件化不仅是一种架构,更是一种理念。架构可以改变,但核心思想是统一的。拆分代码时要注意模块的粒度,并不是粒度越小越好。 ,模块分离良好,对后期的组件改造有很大帮助。
关于组件化的文章到此结束。组件化重构项目已上传至 Github。
以后会有
**插入** 项目改造。敬请关注。

版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议。转载请附上原文出处链接和本声明。

这篇文章的链接: https://homecpp.art/3704/6415/0928

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明

本文链接:https://www.qanswer.top/12250/57580411

posted @   哈哈哈来了啊啊啊  阅读(66)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示