欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 项目架构 组件化基础介绍

程序员文章站 2022-10-16 16:30:03
android 项目架构 化基础介绍 什么是模块化、组件化、插件化 模块化 modular programming modular programming is a software design...

android 项目架构 化基础介绍

什么是模块化、组件化、插件化

模块化 modular programming
modular programming is a software design technique that emphasizes separating the functionality of a program into independent, interchangeable modules, such that each contains everything necessary to execute only one ect of the desired functionality.
模块化是一种软件设计理念,它强调将程序拆分成相互独立的、不可变的模块,其中每个模块只包含与其功能相关的模块。

组件化 component-based software engineering
component-based software engineering (cbse), also known as component-based development (cbd), is a branch of software engineering that emphasizes the separation of concerns in respect of the wide-ranging functionality available throughout a given software system. it is a reuse-based approach to defining, implementing and composing loosely coupled independent components into systems. this practice aims to bring about an equally wide-ranging degree of benefits in both the short-term and the long-term for the software itself and for organizations that sponsor such software.
组件化强调了如何将一个大的拆分成各个的独立的组件。
它提供了一种可重用的方式来定义、实施和组合各个低耦合的松散的组件到一个系统中。

插件化
组件化和插件化的概念与用处一样,但最大区别(应该也是唯一区别)就是组件化在运行时不具备动态添加和修改组件的功能,但是插件化是可以的。

项目架构

了解基本概念,梳理现在基本上在使用的两种架构类型:

一种是现在使用的 单一工程,多个lib 的架构,这种架构很常见,其中多个lib也可能是由gradle引入; 另外一种是 主工程,多组件 的架构,即组件化。这也是我们在实践和即将要实践的架构。

1. 主工程,多library

依靠包名来区分业务,且分包会不明确,且复用性低; 业务包和业务包之间直接相互调用,强耦合; 需要编译整个项目,效率低; 写需求时沟通成本高;

Android 项目架构 组件化基础介绍

2. 主工程多组件(组件化)

Android 项目架构 组件化基础介绍

组件化在android中的应用是在基于gradle的不同配置上进行的,特点是:一个组件可以作为一个module(project)被主组件compile运行,也可以单独作为一个application直接运行。
这点也可以成为android上的组件化原理

android 项目架构 组件化基础介绍

什么是模块化、组件化、插件化

模块化 modular programming
modular programming is a software design technique that emphasizes separating the functionality of a program into independent, interchangeable modules, such that each contains everything necessary to execute only one aspect of the desired functionality.
模块化是一种软件设计理念,它强调将程序拆分成相互独立的、不可变的模块,其中每个模块只包含与其功能相关的模块。

组件化 component-based software engineering
component-based software engineering (cbse), also known as component-based development (cbd), is a branch of software engineering that emphasizes the separation of concerns in respect of the wide-ranging functionality available throughout a given software system. it is a reuse-based approach to defining, implementing and composing loosely coupled independent components into systems. this practice aims to bring about an equally wide-ranging degree of benefits in both the short-term and the long-term for the software itself and for organizations that sponsor such software.
组件化强调了如何将一个大的系统拆分成各个的独立的组件。
它提供了一种可重用的方式来定义、实施和组合各个低耦合的松散的组件到一个系统中。

插件化
组件化和插件化的概念与用处一样,但最大区别(应该也是唯一区别)就是组件化在运行时不具备动态添加和修改组件的功能,但是插件化是可以的。

项目架构

了解基本概念,梳理现在基本上在使用的两种架构类型:

一种是现在使用的 单一工程,多个lib 的架构,这种架构很常见,其中多个lib也可能是由gradle引入; 另外一种是 主工程,多组件 的架构,即组件化。这也是我们在实践和即将要实践的架构。

1. 主工程,多library

依靠包名来区分业务,且分包会不明确,且复用性低; 业务包和业务包之间直接相互调用,强耦合; 需要编译整个项目,效率低; 写需求时沟通成本高;

Android 项目架构 组件化基础介绍

2. 主工程多组件(组件化)

Android 项目架构 组件化基础介绍

组件化在android中的应用是在基于gradle的不同配置上进行的,特点是:一个组件可以作为一个module(project)被主组件compile运行,也可以单独作为一个application直接运行。
这点也可以成为android上的组件化原理
即业务组件之间是独立的,没有关联的,这些业务组件在集成模式下是一个个library,被app壳工程所依赖,组成一个具有完整业务功能的app应用;但是在组件开发模式下,业务组件又变成了一个个application,它们可以独立开发和调试。

组件化基于这样的特性的好处多多(插件化也应该如此):

各个组件间代码和资源相互隔离,不存在直接的相互调用,复用性强 各个组件可以单独修改,单独运行,单独编译,没有关联,开发效率高,测试成本低 新增、修改、删除业务组件简单便捷,完成需求、定位bug效率高 团队成员上手快,沟通成本降低

如何实施组件化

即在上面说的组件化的原理,主要是通过配置gradle脚本来完成组件化。

在gradle.properties中添加isrunalone属性,用于控制组件是否单独运行。
主工程中,始终是作为application存在,其他的组件被其引用,组成一个整体的app。
组件中,根据isrunalone决定是作为application单独运行,还是作为library来运行。

主工程中:

apply plugin: 'com.android.application'

android{
  sourcesets {
        main {
            java.srcdirs = ['src/main/java']
        }
    }
}

dependencies {
    implementation project(':module_service')  //组件通信库
    implementation project(':module_common:lib_common') // 基础库

    if (isrunalone.toboolean()) {
    } else {
        implementation project(':component_one')
        implementation project(':component_two')
        implementation project(':component_three')
    }

}

组件中:

// 单独运行时使用application,否则则作为library使用
if (isrunalone.toboolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}

android {
  sourcesets {
        main {
            // 单独运行时指定额外所使用的java资源、res资源和manifest
            if (isrunalone.toboolean()) {
                manifest.srcfile 'src/main/runalone/androidmanifest.xml'
                java.srcdirs = ['src/main/java', 'src/main/runalone/java']
                res.srcdirs = ['src/main/res', 'src/main/runalone/res']
            } else {
                java.srcdirs = ['src/main/java]
            }
        }
    }
    resourceprefix "gank_" //组件中资源命名规范
}

dependencies {
    implementation filetree(dir: 'libs', include: ['*.jar'])

    //数据库
    implementation project(':module_common:lib_common')
    implementation project(':module_service')
}

在这种思想的引导下,我们只需要关心如何做好隔离,如何更好地设计,以提高开发效率。
接下来主要就是 解决组件间如何通信以及如何传递数据。

组件间如何传递数据、ui跳转

这里采用得到的方案,即组件间在彼此无法互相访问的时候的接口定义和调用。

每个组件在module_service中声明自己提供的服务service,module_service和module_common一样都是要被所有组件引用的,一个是通信的基础库,另一个是下沉的基础库。

这些组件在module_service中声明的service都是一些抽象类或者接口,service的实现类在自己的组件中,组件负责将这些service实现并注册到一个统一的路由router中去。

如果其他要使用某个组件的功能,只需要向router请求这个service的实现,具体的实现细节我们全然不关心,只要能返回我们需要的结果就可以了。

组件如何将这些service的实现注册到router中。
使用applicationdeletegate的概念,在其中添加了组件的生命周期方法。在具体实现类中的applicationdelegate#oncreate方法中,将自己实现的serviceimpl注册到router中。

这块就介绍这么点了,在实践中不断丰富这块的内容。具体的通信、包括传输fragment、startactivityforresult、eventbus等,都得在具体的实践中去完善。

得到提供方案的优点

得到使用了gradle插件去解耦组件和组件之间的强依赖,而去依赖了配置,在编译期间进行组合;这样的思路很清晰,也很易懂。
而且组件可以依赖别的组件,一个app中可以有多个可以依赖别的组件的application。
这样极大的方便了组件之间之间的组合,也方便了测试。
感谢得到的开源,微信也提供了更好的在业务层面的组件分离的方式,即将accout等公共信息直接封装在业务基础层,即用户这块作为基础层存在,避免了作为组件而频繁通信的情况。


下面是自己项目进行组件化的笔记。

daily重构

遇到的问题:
1. 如何拆分基础库,什么是基础库
包含网络、图片、数据库等的即为基础库,其中网络层面的基础设置也应该被包含到该层次,不要过度设计。
还有基于baseapplication的context获取;baseview层面;commonutil层面等

主题theme、style的拆分

library中使用butterknife导致r2和r1 toolbar的id不一致
已删除butterknife,在组件化中不使用

app_name
gradle中添加 resourceprefix进行隔离,在写基础库时也要注意app_name的冲突

传递fragment,传递数据
将fragment在application在初始化时放入map中,像router那样获取它,applicationdelegate
组件生命周期,在mainapplication初始化时初始各个组件,组件开始向中间件注册服务(跳转、获取view等)

ui跳转,即组件间的相互跳转
可否以服务的方式注册,而不是单独的router,如果不考虑更多的扩展的话。

自己配置gradle而不使用插件来动态配置问题:
无法做到其中一个组件是application去依赖其他组件,因为application只有一个,其他的要么是module要么是application。
且动态配置基本上完全隔离了组件在gradle中进行compile,这样删掉一个组件也不会报错。

即业务组件之间是独立的,没有关联的,这些业务组件在集成模式下是一个个library,被app壳工程所依赖,组成一个具有完整业务功能的app应用;但是在组件开发模式下,业务组件又变成了一个个application,它们可以独立开发和调试。

 

组件化基于这样的特性的好处多多(插件化也应该如此):

各个组件间代码和资源相互隔离,不存在直接的相互调用,复用性强 各个组件可以单独修改,单独运行,单独编译,没有关联,开发效率高,测试成本低 新增、修改、删除业务组件简单便捷,完成需求、定位bug效率高 团队成员上手快,沟通成本降低

如何实施组件化

即在上面说的组件化的原理,主要是通过配置gradle脚本来完成组件化。

gradle.properties中添加isrunalone属性,用于控制组件是否单独运行。
主工程中,始终是作为application存在,其他的组件被其引用,组成一个整体的app。
组件中,根据isrunalone决定是作为application单独运行,还是作为library来运行。

主工程中:

apply plugin: 'com.android.application'

android{
  sourcesets {
        main {
            java.srcdirs = ['src/main/java']
        }
    }
}

dependencies {
    implementation project(':module_service')  //组件通信库
    implementation project(':module_common:lib_common') // 基础库

    if (isrunalone.toboolean()) {
    } else {
        implementation project(':component_one')
        implementation project(':component_two')
        implementation project(':component_three')
    }

}

组件中:

// 单独运行时使用application,否则则作为library使用
if (isrunalone.toboolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}

android {
  sourcesets {
        main {
            // 单独运行时指定额外所使用的java资源、res资源和manifest
            if (isrunalone.toboolean()) {
                manifest.srcfile 'src/main/runalone/androidmanifest.xml'
                java.srcdirs = ['src/main/java', 'src/main/runalone/java']
                res.srcdirs = ['src/main/res', 'src/main/runalone/res']
            } else {
                java.srcdirs = ['src/main/java]
            }
        }
    }
    resourceprefix "gank_" //组件中资源命名规范
}

dependencies {
    implementation filetree(dir: 'libs', include: ['*.jar'])

    //数据库
    implementation project(':module_common:lib_common')
    implementation project(':module_service')
}

在这种思想的引导下,我们只需要关心如何做好隔离,如何更好地设计,以提高开发效率。
接下来主要就是 解决组件间如何通信以及如何传递数据。

组件间如何传递数据、ui跳转

这里采用得到的方案,即组件间在彼此无法互相访问的时候的接口定义和调用。

每个组件在module_service中声明自己提供的服务service,module_service和module_common一样都是要被所有组件引用的,一个是通信的基础库,另一个是下沉的基础库。

这些组件在module_service中声明的service都是一些抽象类或者接口,service的实现类在自己的组件中,组件负责将这些service实现并注册到一个统一的路由router中去。

如果其他要使用某个组件的功能,只需要向router请求这个service的实现,具体的实现细节我们全然不关心,只要能返回我们需要的结果就可以了。

组件如何将这些service的实现注册到router中。
使用applicationdeletegate的概念,在其中添加了组件的生命周期方法。在具体实现类中的applicationdelegate#oncreate方法中,将自己实现的serviceimpl注册到router中。

这块就介绍这么点了,在实践中不断丰富这块的内容。具体的通信、包括传输fragment、startactivityforresult、eventbus等,都得在具体的实践中去完善。

得到提供方案的优点

得到使用了gradle插件去解耦组件和组件之间的强依赖,而去依赖了配置,在编译期间进行组合;这样的思路很清晰,也很易懂。
而且组件可以依赖别的组件,一个app中可以有多个可以依赖别的组件的application。
这样极大的方便了组件之间之间的组合,也方便了测试。
感谢得到的开源,微信也提供了更好的在业务层面的组件分离的方式,即将accout等公共信息直接封装在业务基础层,即用户这块作为基础层存在,避免了作为组件而频繁通信的情况。


下面是自己项目进行组件化的笔记。

daily重构

遇到的问题:
1. 如何拆分基础库,什么是基础库
包含网络、图片、数据库等的即为基础库,其中网络层面的基础设置也应该被包含到该层次,不要过度设计。
还有基于baseapplication的context获取;baseview层面;commonutil层面等

主题theme、style的拆分

library中使用butterknife导致r2和r1 toolbar的id不一致
已删除butterknife,在组件化中不使用

app_name
gradle中添加 resourceprefix进行隔离,在写基础库时也要注意app_name的冲突

传递fragment,传递数据
将fragment在application在初始化时放入map中,像router那样获取它,applicationdelegate
组件生命周期,在mainapplication初始化时初始各个组件,组件开始向中间件注册服务(跳转、获取view等)

ui跳转,即组件间的相互跳转
可否以服务的方式注册,而不是单独的router,如果不考虑更多的扩展的话。

自己配置gradle而不使用插件来动态配置问题:
无法做到其中一个组件是application去依赖其他组件,因为application只有一个,其他的要么是module要么是application。
且动态配置基本上完全隔离了组件在gradle中进行compile,这样删掉一个组件也不会报错。