摘要:本文将带你了解Android应用开发之Android 项目架构 组件化基础介绍,希望本文对大家学Android有所帮助。
本文将带你了解Android应用开发之Android 项目架构 组件化基础介绍,希望本文对大家学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
依靠包名来区分业务,且分包会不明确,且复用性低; 业务包和业务包之间直接相互调用,强耦合; 需要编译整个项目,效率低; 写需求时沟通成本高;
2. 主工程多组件(组件化)
组件化在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
依靠包名来区分业务,且分包会不明确,且复用性低; 业务包和业务包之间直接相互调用,强耦合; 需要编译整个项目,效率低; 写需求时沟通成本高;
2. 主工程多组件(组件化)
组件化在Android中的应用是在基于gradle的不同配置上进行的,特点是:一个组件可以作为一个module(project)被主组件compile运行,也可以单独作为一个application直接运行。
这点也可以成为Android上的组件化原理。
即业务组件之间是独立的,没有关联的,这些业务组件在集成模式下是一个个library,被app壳工程所依赖,组成一个具有完整业务功能的APP应用;但是在组件开发模式下,业务组件又变成了一个个application,它们可以独立开发和调试。
组件化基于这样的特性的好处多多(插件化也应该如此):
各个组件间代码和资源相互隔离,不存在直接的相互调用,复用性强 各个组件可以单独修改,单独运行,单独编译,没有关联,开发效率高,测试成本低 新增、修改、删除业务组件简单便捷,完成需求、定位bug效率高 团队成员上手快,沟通成本降低
如何实施组件化
即在上面说的组件化的原理,主要是通过配置gradle脚本来完成组件化。
在gradle.properties中添加isRunAlone属性,用于控制组件是否单独运行。
主工程中,始终是作为application存在,其他的组件被其引用,组成一个整体的app。
组件中,根据isRunAlone决定是作为application单独运行,还是作为library来运行。
主工程中:
?12345678910111213141516171819202122apply 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') } }
组件中:
?123456789101112131415161718192021222324252627282930// 单独运行时使用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来运行。
主工程中:
?12345678910111213141516171819202122<code><code><code><code><code><code>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') } }</code></code></code></code></code></code>
组件中:
?123456789101112131415161718192021222324252627282930<code><code><code><code><code><code>// 单独运行时使用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')}</code></code></code></code></code></code>
在这种思想的引导下,我们只需要关心如何做好隔离,如何更好地设计,以提高开发效率。
接下来主要就是 解决组件间如何通信以及如何传递数据。
组件间如何传递数据、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,这样删掉一个组件也不会报错。
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之Android频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号