Android笔记:Android 组件化方案探究与思考

作者 : 开心源码 本文共4298个字,预计阅读时间需要11分钟 发布时间: 2022-05-13 共221人阅读

组件化项目,通过gradle脚本,实现module在编译期隔离,运行期按需加载,实现组件间解耦,高效单独调试。

本项目github地址
先来一张效果图,建议读者clone项目后跟着项目看这篇文章,有任何不明白的地方可留言或者者联络我,我看到后会立刻回复你。

组件化初衷

  • APP版本不断的迭代,新功能的不断添加,业务也会变的越来越复杂,维护成本高。
  • 业务耦合度高,代码越来越臃肿,团队内部多人协作开发困难。
  • Android项目在编译代码的时候电脑会非常卡,又由于单一工程下代码耦合严重,每修改一处代码后都要重新编译打包测试,导致非常耗时。
  • 方便单元测试,改动单独一个业务板块,不需要着重于关注其余板块被影响。

什么是组件化

组件化就是将一个app分成多个Module,如下图,每个Module都是一个组件(也可以是一个基础库供组件依赖),开发的过程中我们可以单独调试部分组件,组件间不需要互相依赖,但可以相互调用,最终发布的时候所有组件以lib的形式被主app工程依赖并打包成一个apk。

组件化优势

  • 组件化就是将通用板块独立出来,统一管理,以提高复用,将页面拆分为粒度更小的组件,组件内部除了包含UI实现,还包含数据层和逻辑层。
  • 每个工程都可以独立编译、加快编译速度,独立打包。
  • 每个工程内部的修改,不会影响其余工程。
  • 业务库工程可以快速拆分出来,集成到其余App中。
  • 迭代频繁的业务板块采用组件方式,业务线研发可以互不干扰、提升协作效率,并控制产品质量,增强稳固性。
  • 并行开发,团队成员只关注自己的开发的小板块,降低耦合性,后期维护方便等。

指导思想

  • 组件拆分:将一个project划分成业务组件、基础组件、路由组件。其中业务组件是相互隔离的,可以单独调试,基础组件提供业务组件所公用的功能,路由组件为业务组件之间通信提供支持。
  • 组件隔离:业务组件之间的隔离,可以单独调试。
  • 核心法则:编译期隔离,运行期按需依赖。

依赖关系

组件化需要考虑的问题

  • 模式切换:如何使得APP在单独调试跟整体调试自由切换
  • 资源冲突:当我们创立了多个Module的时候,如何处理相同资源文件名合并的冲突
  • 依赖关系:多个Module之间如何引用少量共同的library以及工具类
  • 组件通信:组件化之后,Module之间是相互隔离的,如何进行UI跳转以及方法调用
  • 入口参数:我们知道组件之间是有联络的,所以在单独调试的时候如何拿到其它的Module传递过来的参数

组件化后项目结构如下图

理论说了那么多,下面开始撸代码

实现步骤

1、全局设置Gradle,每一个业务Module需要的版本都定义在这里方便后期维护多个Module版本号

ext {    // Sdk and tools    minSdkVersion = 16    targetSdkVersion = 26    compileSdkVersion = 26    buildToolsVersion = '26.0.2'    supportLibraryVersion = '26.1.0'    // App dependencies    aRouter = '1.2.2'    leakcanaryVersion = '1.3'    glideVersion = '3.7.0'} ####每个业务Module编译依赖版本 compileSdkVersion rootProject.ext.compileSdkVersion buildToolsVersion rootProject.ext.buildToolsVersion minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion

2、模式切换

组件化后的每一个业务的module都可以是一个单独的APP(isModuleRun=false), release 包的时候各个业务module作为lib依赖,这里完全由一个变量控制,在根项目 gradle.properties里面的 isModuleRun=true

isModuleRun状态不同,加载application和AndroidManifest都不一样,以此来区分是独立的APK还是lib,
实现方式如下
build.grade里面配置

if (isModuleRun.toBoolean()) {    apply plugin: 'com.android.application'} else {    apply plugin: 'com.android.library'}##单Module运行需要配置sourceSets {        main {            if (isModuleRun.toBoolean()) {                manifest.srcFile 'src/main/debug/AndroidManifest.xml'            } else {                manifest.srcFile 'src/main/AndroidManifest.xml'                java {                    //一律Module一起编译的时候剔除debug目录                    exclude '**/debug/**'                }            }        }    }

3、资源冲突

业务Module和BaseModule资源文件名称重复会产生冲突,处理方案在
每个 module 都有 app_name,为了不让资源名重名,在每个组件的 build.gradle 中添加 resourcePrefix “xxx_强行检查资源名称前缀。
固定每个组件的资源前缀。但是 resourcePrefix 这个值只能限定 xml 里面的资源,并不能限定图片资源。
个人认为商定大于配置,团队内协定好规范,可以避免冲突。

4、组件通讯
组件通讯框架在github上有star最多的有ARouter和ActivityArouter,前者是个人项目,后者是阿里巴巴开源,权衡之下选择阿里的ARouter,
各业务Module之前不需要任何依赖可以通过路由跳转,完美处理业务之间耦合
使用方式如下。

 if (BuildConfig.DEBUG) {   // 这两行必需写在init之前,否则这些配置在init过程中将无效           ARouter.openLog();     // 打印日志           ARouter.openDebug();   // 开启调试模式(假如在InstantRun模式下运行,必需开启调试模式!线上版本需要关闭,否则有安全风险)        }ARouter.init(this); // 尽可能早,推荐在Application中初始化
compile "com.alibaba:arouter-api:$rootProject.aRouter"每个业务Module都需要增加注解annotationProcessor 'com.alibaba:arouter-compiler:1.1.3'

跳转方法
在目标Activity上增加path

@Route(path = ARouterManager.BModuleActivity)public class BModuleActivity extends BaseActivity {    @Autowired    public String name;    @Autowired(name = "age")    int age;    TextView txt;    @Override    protected int getLayoutId() {        return R.layout.b_module_layout;    }    @Override    protected void initView() {        txt = findViewById(R.id.txt);        //String name = getIntent().getStringExtra("name"); 也可以这样接受参数        ARouter.getInstance().inject(this);        txt.setText("name:" + name + ",age:" + age);  #开始跳转 btn2.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                // 2\. 跳转并携带参数                ARouter.getInstance().build(ARouterManager.BModuleActivity)                        .withString("name", "888")                        .withInt("age", 11)                        .navigation();            }        });
/** * 路由管理类 */public final class ARouterManager {    public static final String AFragment = "/amodule/AFragment";    public static final String BFragment = "/bmodule/BFragment";    public static final String CFragment = "/cmodule/CFragment";    public static final String AModuleActivity = "/amodule/AAModuleActivity";    public static final String BModuleActivity = "/bmodule/BModuleActivity";    public static final String CModuleActivity = "/cmodule/CModuleActivity";}

上述只使用了ARouter的简单用法,更多进阶用法请参考ARouter文档,
ARouter

5、Application

当组件单独运行的时候,每个Module自成一个APK,那么就意味着会有多个Application,很显然我们不愿意重复写这么多代码,所以我们只要要定义一个BaseApplication就可,其它的Application直接继承此BaseApplication就OK了,BaseApplication里面还可定义公用的参数。

最后

就这样吧,Android Q 要来了,后续还会升级少量适配改动的细节,有任何疑问欢迎加下面的技术交流群一起探讨~

假如你看到了这里,觉得文章写得不错就给个赞呗?假如你觉得那里值得改进的,请给我留言。肯定会认真查询,修正不足。谢谢。

最后文末放上一个技术交流群:Android架构设计(185873940)

PS:群内有许多技术大牛,有任何疑问,欢迎广大网友一起来交流,群内还不定期免费分享高阶Android学习视频资料和面试资料包~

再推荐一篇文章,具体的架构视频,面试专题,学习笔记都在这篇文章中:“寒冬未过”,阿里P9架构分享Android必备技术点,让你offer拿到手软!

偷偷说一句:群里高手如云,欢迎大家加群和大佬们一起交流探讨啊~

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Android笔记:Android 组件化方案探究与思考

发表回复