Android Componentization (组件化架构) 演变

《Android Componentization (组件化架构) 演变》

1.前言

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

2.目录

《Android Componentization (组件化架构) 演变》 目录.png

3.组件化发展史

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

3.1 传统化项目结构

《Android Componentization (组件化架构) 演变》 传统化结构.png

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

3.2 模块化项目结构

《Android Componentization (组件化架构) 演变》 模块化结构.png

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

3.3 组件化项目结构

《Android Componentization (组件化架构) 演变》 组件化结构.png

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

4.定义

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

5.作用

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

6.特点

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

7.组件化架构

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

8.组件化实践

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

    《Android Componentization (组件化架构) 演变》 例子项目结构.png

8.1 base公用

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

    《Android Componentization (组件化架构) 演变》 base引用.png

8.2 module独立与集成

  • 将4个配置为可以单独运行或者集成运行的状态:
    • 1.打开各种module中 gradle.properties文件,添加如下内容:
      《Android Componentization (组件化架构) 演变》 集成于与独立配置1.png
    • 2.打开各种module中 build.gradle文件,添加如下内容:
      《Android Componentization (组件化架构) 演变》 集成于与独立配置2.png
      《Android Componentization (组件化架构) 演变》 集成于与独立配置3.png
    • 3.在module独立运行时,需要为其添加对应独立运行的AndroidManifest.xml文件:

      《Android Componentization (组件化架构) 演变》 集成于与独立配置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时,使用以下方式:

    《Android Componentization (组件化架构) 演变》 代码隔离.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_简书

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

写技术文章初心

  • 技术知识积累
  • 技术知识巩固
  • 技术知识分享
  • 技术知识交流
    原文作者:Linhaojian
    原文地址: https://www.jianshu.com/p/ef438d24f8b4
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞