美文网首页组件化AndroidAndroid架构
Android Componentization (组件化架构)

Android Componentization (组件化架构)

作者: Linhaojian | 来源:发表于2019-02-18 12:04 被阅读288次

    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_简书

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


    写技术文章初心

    • 技术知识积累
    • 技术知识巩固
    • 技术知识分享
    • 技术知识交流

    相关文章

      网友评论

        本文标题:Android Componentization (组件化架构)

        本文链接:https://www.haomeiwen.com/subject/bevzqqtx.html