Android Componentization (组件化架构) 演变

1.前言

  • 组件化 在Android开发的近几年来,已经由单纯编写代码的概念(工具类、第三方组件等等)迁移并应用于项目的架构上,而在应用项目架构过程中又演变出多种不同的实现方案,随着现代APP应用市场的快速发展,应用开发的时间、效率、稳定性、可扩展性、灵活性都要体现出高标准的行业水平,因此开发者就想出把项目划分多个模块,并且需求满足协同与独立开发,组件化就由此诞生。
  • 文章中实例 linhaojian的Github

2.目录

目录.png

3.组件化发展史

  • 项目架构发展过程中,包含非常多种实现方式,我将它们划分了三种 传统、模块、组件
    项目架构分类.png

3.1 传统化项目结构

传统化结构.png
  • 传统化结构:通过 项目内业务分包 的方式进行开发,这种方式 维护、扩展都非常困难,并且不方便团队开发,只适应小项目

3.2 模块化项目结构

模块化结构.png
  • 模块化结构:在AndroidStudio 开发工具内,通过 创建module 的方式进行划分不同的业务功能,然后在主项目与module 或者 module间构建关联(这种关联方式耦合性高),当module不合理设置的适合,会出现module之间类库的冗余或者重复使用。

3.3 组件化项目结构

组件化结构.png
  • 组件化结构:组件化就是在模块化的思想上优化演变出来,在模块化思想上,通过1.抽出module间公用部分;2.使用路由Router解耦module间的交互;3.gradle集成与独立配置;4.代码与资源的隔离,使得module同时支持集成开发与独立开发。

4.定义

  • 将重复的代码进行封装,业务功能划分为最小粒子。

5.作用

  • 1.复用代码
  • 2.降低业务功能间的依赖或者关联
  • 3.提供单独业务运行与调试

6.特点

  • 1.module具备独立性,可单独运行或调试
  • 2.module间高度解耦,通过路由交互
  • 3.代码与资源隔离
  • 4.module划分尽可能粒子化,便于维护与复用

7.组件化架构

  • 借助以下的包含实例的图,便于更深入了解 组件化 的架构;
    组件化分层.png
  • 图中总共分4层 组件集成、业务组件、功能组件、运行环境
    • 组件集成:将所有业务组件组合到APP的空壳项目中(空壳项目中只包含启动页,无任何业务逻辑);
    • 业务组件:将项目按照功能需要划分粒度较小的module;
    • 功能组件:将不同业务组件中公用部分封装为各种类库;
    • 运行环境:项目开发中所依赖的语言库或者开发环境;
  • 从图中可以发现,组件化只存在 垂直关系,使各业务功能更独立与清晰,更适合现代团队开发的要求。

8.组件化实践

  • 下面简单配合例子实践组件化开发过程;
    • 项目:类似于便利生活的应用;
    • 功能:登录、注册、酒店、外卖;
  • 项目结构如下图:


    例子项目结构.png

8.1 base公用

  • 1.将module间公用的代码封装base的库(如:Log库、Base库、网络请求库等等);
  • 2.在4个模块中添加引用;


    base引用.png

8.2 module独立与集成

  • 将4个配置为可以单独运行或者集成运行的状态:
    • 1.打开各种module中 gradle.properties文件,添加如下内容:
      集成于与独立配置1.png
    • 2.打开各种module中 build.gradle文件,添加如下内容:
      集成于与独立配置2.png

      集成于与独立配置3.png
    • 3.在module独立运行时,需要为其添加对应独立运行的AndroidManifest.xml文件:


      集成于与独立配置4.png
  • 注:可以通过修改isRunAlone的赋值,就能改变module的运行状态,true:可独立运行,false:集成运行。

8.3 多Application初始化

  • 因为module已具备独立运行开发的特点,所以开发过程中module中就会按照自己功能内需求初始化所需的第三方类库或者工具库,因此module中就会存在各自的Application类,那么在集成开发过程中,我们也需要把module内的Application进行初始化调用,不然就会与独立开发不兼容的问题,可以通过 反射 解决:

8.3.1 实现原理

  • 主application 中,通过 反射 把其他module的Application初始化。

8.3.2 实现过程

* 1.创建一个抽象BaseApplication,其他module都继承于它。
public abstract class BaseApplication extends Application{
    public abstract void init(Context context);// 1
    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化所有module公用的类库
        initPublic();
        // 初始化不同module的Application
        init(getApplicationContext());// 2
    }
    /**
     * 初始化Module功能的类库
     */
    public void initPublic(){
        ARouter.init(this);
    }
}
  • 注释1:提供抽象init方法,使其他module都在init函数中进行初始化。
  • 注释2:统一和兼容集成与独立的2种开发环境
    • 2.让Login组件继承BaseApplication
public class LoginAppcation extends BaseApplication {
    @Override
    public void init(Context context) {
        //初始化 login组件 中使用的类库
        // dagger2 、rxjava ....
    }
}
* 3.在主项目或者main组件中,通过反射进行初始化
public class MainAppcation extends BaseApplication {
    //module中application类的路径
    private static final String[] MODULESLIST =
            {"com.lhj.component.login.LoginAppcation"};
    @Override
    public void init(Context context) {
        //初始化 main组件 中所需的类库
        // 初始化其他module的Application
        modulesApplicationInit(context);
    }
    /**
     * 通过反射的方式,获取指定Application类的实例,并调用init函数,解决组件化多appplication独立的问题
     */
    private void modulesApplicationInit(Context context){
        for (String moduleImpl : MODULESLIST){
            try {
                Class<?> clazz = Class.forName(moduleImpl);
                Object obj = clazz.newInstance();
                if (obj instanceof BaseApplication){
                    ((BaseApplication) obj).init(context);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 通过 反射 很好的解决组件独立开发的多个Application初始化问题,并且同时兼容集成开发环境,但是反射就存在性能的问题,但暂时没有想到一个更好的解决方案,请各位大神可以评论指教。

8.4 module间界面的跳转

8.5 代码隔离

  • 在集成开发中,主项目需要对4个模块进行引用,但为了防止在主项目编译时引用了其他module内的类的问题,所以需要实现代码隔离,使得真正意义上独立。
  • 可以在引用module时,使用以下方式:


    代码隔离.png

8.6 资源隔离

  • 在集成开发中,如果module之间存在资源名字相同的情况时,可能会影响项目的运行或者误导开发人员,
    所以建议为不同module的资源文件添加对应的命名规则
    • 1.xml内(string、colors等资源文件)的命名方式可以通过如下配置方式;
  • 如:将登录module的xml文件
android {
    //...
    // 实现资源隔离
    resourcePrefix "login_"
}
* 2. 对于控件名称与文件名称,可根据自己的喜欢区分;

8.7 数据复用

  • 项目开发过程中,经常会出现数据需要全局应用,因此在多module间需要实现数据复用,可以通过以下方式实现:
    • 1.使用Arouter框架中的Provider功能(将复用的数据保存base库的Provider中,然后通过Arouter的navigation函数获取);
    • 2.base库中,可以按需添加对象全局数据的管理类。

8.8 资源复用

  • 将可能会复用的资源,添加至base库中,防止资源重复的问题。

9.总结

  • 到此,Android项目组件化开发介绍完毕!
  • 如果喜欢我的分享,可以点击 关注 或者 ,你们支持是我分享的最大动力 。
  • linhaojian的Github

欢迎关注linhaojian_CSDN博客或者linhaojian_简书

不定期分享关于安卓开发的干货。


写技术文章初心

  • 技术知识积累
  • 技术知识巩固
  • 技术知识分享
  • 技术知识交流
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容