【架构篇2】组件化方案及步骤

愿你成为自己的太阳,无需借谁的光
下文列出组件化的思路和步骤,按照如下思路和步骤,可以加快组件化工作的速度

1 诊断分析

1.1 诊断思路

【业务诊断】

列出包结构和主要类,按照业务维度进行诊断分析:

  1. 梳理业务组件:相关联的包或类归属到对应的组件下,根据用户的使用路径,查看这个类的依赖和引用情况;
  2. 梳理功能组件:查看前面业务组件多次引用的类,如果一个类被多个业务组件所引用,那么大概率这个类要被划分到功能组件的范围;
  3. 梳理技术组件:能不能放在任何一个应用里使用

【接口诊断】

根据类依赖和引用关系,找到业务边界类:

  1. 列出核心类的依赖和引用关系,Ctrl+鼠标左键找到引用类,逐个排查调用的地方,设计好业务间API接口

1.2 搜索诊断

包名 主要功能 核心类 类依赖及引用情况 重构优先级 组件划 重构操作 修改点 操作状态
adapter 主要存放列表的适配器 DefaultRecyclerAdapter 无依赖 1 基础组件 下沉 common 可复用 move-done

1.3 业务诊断

包名 主要功能 核心类 类依赖及引用情况 重构优先级 组件划分 重构操作 修改点 操作状态
activity 存放数据模型、工具类、ViewModel、Activity

2 组件化

3.1 准备工作

  1. 确保目标 Module 存在

若目标 Module 不存在,需先创建新 Module,创建步骤如下所示

如上图 File → New → New Module → Android Library,并确保在 settings.gradle 中已包含:

php 复制代码
include ':app', ':original_module', ':target_module'

include ':space'
  1. 在app中添加该Module,确保新增module会构建到工程中
scss 复制代码
//build.gradle :app
implementation(':space')
  1. 复制相关依赖

为了避免迁移时AS报错导致移动失败,可以提前将原Module中的依赖拷贝到创建的Module,然后同步项目,如:

java 复制代码
dependencies {
    implementation project(':login')
    implementation project(':common')
    implementation project(':config')
    implementation project(':common_ui')
}

确保可以迁移成功,后面再删除多余的依赖

  1. 更改targetSdk和JDK版本
kotlin 复制代码
apply plugin: 'com.android.library'
apply from: "${rootProject.projectDir}/constants.gradle"
apply from: "${rootProject.projectDir}/versions.gradle"
apply from: "${rootProject.projectDir}/template/module.gradle"
apply from: "${rootProject.projectDir}/create_module_api.gradle"
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
    compileSdk  build_versions.compile_sdk
    defaultConfig {
        minSdkVersion build_versions.min_sdk
        targetSdk  build_versions.target_sdk
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        consumerProguardFiles "consumer-rules.pro"
        versionCode build_versions.version_code
        versionName build_versions.version_name
        archivesBaseName = prop_archivesBaseName
        //指定room.schemaLocation生成的文件路径
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = ["room.schemaLocation": "$projectDir/schemas".toString(),
                             AROUTER_MODULE_NAME  : project.getName(),
                             AROUTER_GENERATE_DOC : "enable"]
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }
    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_11.toString()
    }
    kapt {
        useBuildCache = true
        javacOptions {
            option("-Xmaxerrs", 500)
        }
        arguments {
            arg("AROUTER_MODULE_NAME": project.getName())
        }
    }
    flavorDimensions "versionCode", "area"
    //根据配置项,代码中会有一些差别
    productFlavors {
       //
    }
    dataBinding {
        enabled = true
    }
}
  1. 引入apply from : " ${ rootProject . projectDir } /create_module_api.gradle", 提供对外的接口

3.2 接口替换

  1. 如1.1和1.2中的表格,根据诊断结果,先定义好对外的接口,各个引用实例调用的地方都需要核查到
  2. 根据定义好的接口生成space-api.jar
  3. 找到原来引用的地方,进行接口替换

3.3 移动类文件

记得按照小步快跑,逐步验证的原则

  1. 首先拷贝所有资源
  • 考虑到多语言,res下的资源可以通过剪切的方式拷贝过去,这样的好处是既快又全,且能保留git提交记录,当类文件移动过来时,资源是全的。
  • 类移动完成编译验证ok后,用不上的再从两边Module中删除掉
  1. 移动类文件

方法一:

经过测试,简单快捷的方式是:在AS中将所有需要的类一次性剪切到新的module,既能最大程度避免import类重定向的问题,也能保留git提交记录,是目前测试到的最优方式。

方法二:

  • 使用 Refactor → Move(推荐,自动处理部分依赖)

按照诊断的结论,根据优先级来进行移动,优先级数字越小,表示越高优,则优先重构

  1. 右键点击要移动的类文件,选择 Refactor → Move...(或按 F6)。
  2. 在弹出窗口中:
    1. To directory :选择目标 Module 的包路径(如 target_module/src/main/java)。
    2. Search for references:勾选此项,自动修正原 Module 中的引用。
  3. 确认移动
    点击 Refactor,Android Studio 会尝试自动更新代码中的引用(但可能仍需手动检查)。
  • 迁移完记得在git-Local Changes中解决引用错误,由于类都是move过来的,将引用还原回去,就可以解决大部分问题

方式二只适用于小范围重构

3.4 解决编译错误

  1. 清理项目:
    Build → Clean ProjectBuild → Rebuild Project
  2. 手动修正错误
    1. 包名错误 :检查所有 import 语句是否指向新包名。
    2. 缺失依赖 :若目标 Module 需要第三方库,需在其 build.gradle 中添加依赖。

这步会比较耗时,可以在Git---Local Changes逐个浏览更改

3.5 验证功能

  1. 启动 App:手动测试相关功能是否正常。
  2. 检查日志 :关注运行时是否抛出 ClassNotFoundException 或资源加载错误。

验证功能的过程中会遇到各种忽略的奇怪错误,保持耐心,逐个解决即可,常见的错误见3.6节

3.6 常见问题与解决

  1. 问题1 Cannot resolve type 'controller'

【原因】 类的路径变动后,DataBinding定义的类路径并不会自动修正

  1. 问题2 Found UnSupported class type

【原因】由于类都是剪切过来的,引用的路径会有错误的情况,继承com.alibaba.android.arouter.facade.template.IProvider的接口中有类引用路径错误

  1. 问题3 Didn't find class "com. ..PictorialApplication"

【原因】build缓存文件未清掉,导致编译时异常,记得将clean project,并将未clean掉的build目录都删除掉

  1. 问题4 ARouter$$Group is defined multiple times

【原因】由于类的迁移未更改Route path或name的前缀,不同的module中,使用了相同的前缀,导致出现如上错误

  1. ProGuard混淆的规则记得同步更改

3.7 最佳实践

  1. 逐步操作:将整个流程进行解耦,每一步想清楚弄完后再进行下一步,逐步验证,这样即使有问题也是小问题,很容易排查,避免大规模改动后难以定位问题。
  2. 优先使用 Refactor 工具:减少手动操作导致的遗漏。
  3. 模块职责单一化:确保目标 Module 的职责清晰,移动的过程中难免有遗漏,记得做好注释,后续很快可以找到解决

3 解耦重构

3.1 接口优化

在组件化拆分完成后,根据第1章中诊断分析的现状,继续分析当前类的依赖和引用是否合理,进行组件内重构: 详见1.3中的表格

4 历史缺陷分析

4.1 缺陷分析

取2024.1-2024.12的缺陷进行分析如下:

4.2 代码优化

根据bug产生的原因,从代码角度最大程度规避问题:

缺陷类型 原因 解决方法
跳转index错误 处理的地方有多处,且处理的代码样式不一样,会漏掉 将关键的判断方法抽取为统一的方法,使任何人添加代码都不会出错

5 指导手册

从测试和开发角度进行分析,为了提高效率,输出指导手册

相关推荐
demo007x10 小时前
让大模型活在你的鼠标旁:我用 Tauri 2 + Rust 打造了一款“反直觉”的 AI 全局划词效率神器
macos·程序员·llm
程序员海军11 小时前
AI 越来越强,为什么打工人反而越来越累、越来越内耗了?
前端·程序员·aigc
badhope16 小时前
同样写 AI,为什么有的文章 549 人看、有的只有 16 人看?——我用 40 篇掘金文章的真实数据复盘
程序员
今朝唯我少年郎2 天前
Codex安全盲区代码漏洞生成实测
python·程序员
kyriewen2 天前
我用 AI 写完一个需求后才发现,最难的不是 prompt,而是验收
前端·程序员·ai编程
酷酷的逗逗乐2 天前
前端转 Agent 开发 · 第六节
前端·程序员
爱勇宝2 天前
没有 Fn 键关触控板?我做了一个双击即用的 Windows 小工具
前端·后端·程序员
程序员cxuan3 天前
跟 WebUI 说再见了,最强 DeepSeek 桌面端来了!
人工智能·后端·程序员
codigger3 天前
用 AI 写代码,你知道它会把我的代码传去哪?
ai·程序员·编程·数据安全
程序员cxuan3 天前
DeepSeek V4.1 Flash 正式发布!
人工智能·后端·程序员