Android模块化和组件化开发
目录
一.模块化介绍
1.1:模块化简介
1.2:模块化和组件化的区别
1.3:模块化的优点
1.4:模块化的层级介绍
二.如何实现组件化
2.1:实现模块化需要解决的问题
2.2:各个问题的解决方法
一:模块化介绍
(1)对于简单的小项目,大多都采用的是单一工程,独立开发。由于项目不大,编译速度及维护成本这些也在接受范围之内。而对于一个大型App产品,多人合作、单一工程的App架构势必会影响开发效率,增加项目的维护成本。每个开发者都要熟悉如此之多的代码,将很难进行多人协作开发,而且Android项目在编译代码的时候电脑会非常卡,又因为单一工程下代码耦合严重,每修改一处代码后都要重新编译打包测试,导致非常耗时。所以必须要有更灵活的架构代替过去单一的工程架构。
(2)模块和组件化的区别:
模块指的是独立的业务模块。
组件指的是单一的功能组件。如视频组件、支付组件。每个组件都可以以一个单独的module开发,并且可以单独抽取出来作为SDK对外发布使用。
模块和组件最明显的区别是模块相对组件来说粒度更大。一个模块中可能包含多个组件。在划分的时候,模块化是业务导向,组件化是功能导向。
模块化和组件化,我的拙见,并不需要严格意义上的区分。只要适合自己的就好。所以本文中,只是介绍思想,并不是严格意义上的模块化或组件化开发,抛砖引玉。
(3)模块化的优点:
使用模块化架构,业务模块分离,高内聚,低耦合,代码边界清晰,每一个模块业务都可以拆分出来独立运行。所有模块寄托于宿主App,加载分离的各个组件,各自编译自己的模块,有利于多人团队协作开发。我们只需要关注如何做好隔离,如何更好地计,以及提高开发效率与产品体验,还有代码质量。
(4)模块化层级介绍:
基础层BaseModule:基础层包含的是一些常用的基础库以及对基础库的封装和工具类的封装,比如常用的图片加载、网络请求、数据库、数据存储等操作。其他模块或组件都可以引用同一套基础库。
业务层ProviderModule:基础层往上封装了一层跟项目相关的业务功能层,一些与项目有关的常量类、以项目为基础的工具类。
应用层:业务功能层往上就是应用层,应用层可以是多个业务模块,最后将多个业务模块统筹输出为APP。
二:如何实现模块化:
2.1:模块化开发需要解决的问题
1.每一个组件或模块都是一个完整的整体,所以模块化开发过程中要满足单独运行及调试的要求。这样可以提升开发过程中项目的编译速度,以此来提高开发效率。
2.模块之间数据的传递和方法的相互调用。
3.模块之间的界面跳转:在模块化开发过程中如何在不相互依赖的情况下实现互相跳转。
4.模块化开发完成后相互之间的集成调试如何实现呢?
2.2:question one:组件的单独调试和集成调试
1.动态配置组件的工程类型
目的是:让我们的组件既可以单独调试也可以被其他模块依赖。
我们在 gradle.properties,添加一个Boolen变量, isUserModule=false。
if (isUserModule.toBoolean()) {
apply plugin: 'com.android.library'//配置一个library工程,构建后输出aar包。} else {
apply plugin: 'com.android.application'//配置一个Android App工程,项目构建后输出一个APK的安装包}
2.动态配置组件的 ApplicationId 和 AndroidManifest 文件
一个APP应该只有一个ApplicationId 和AndroidManifest 文件。我们在build.gradle文件中添加代码进行动态配置。
//动态设置ApplicationIdif (!isUserModule.toBoolean()) {//如果是模块,则设置包名applicationId "com.example.user"}//动态设置清单文件,需要建立两个清单文件。一个是单独运行的,另外一个是作为依赖时候使用的sourceSets {main {if (isUserModule.toBoolean()) {manifest.srcFile 'src/main/AndroidManifest.xml'} else {manifest.srcFile 'src/main/debug/AndroidManifest.xml'}}}
2.3:question two:组件间的数据传递和方法相互调用
因为组件和组件之间是没有相互依赖的,所以不可以直接使用类的方式进行相互调用来实现数据传递和方法调用。
数据传递我们可以使用:EventBus、广播、数据持久化、接口+实现等方式来解决。比如判断登录状态,获取登录的用户token等。
本文咱们说一下接口+实现的方式:我们以获取登录状态为例
(1):我们在业务模块ProviderModule创建service包,里面放置我们定义的接口和实现类。
(2):创建一个用户模块的接口,IAccountService。里面定义获取登录状态和用户id的方法。
(3):定义一个ServiceFactory,对外提供设置和获取IAccountService的具体实现类。
(4):在用户模块创建AccountService实现IAccountService接口,然后在Application中初始化ServiceFactory中的service。
(5):在其他模块就可以通过ServiceFactory获取实现类,调用实现类的方法了。
一:
/*** author : Naruto* date : 2019-09-07* desc : 用户模块的对外提供的方法* version:*/
interface IAccountService {/*** 是否登录*/fun isLogin(): Boolean/*** 获取用户的AccountId*/fun getAccountId(): String/*** 获取用户中心Fragment*/fun getUserFragment(activity: Activity): BaseFragment?
}二:在用户模块,实现IAccountService。
/*** author : Naruto* date : 2019-09-07* desc : IAccountService实现类。暴露用户模块对外提供的方法。解耦,外部只需要调用就可以了,不需要知道内部实现的细节。* version:*/
class AccountService : IAccountService {override fun isLogin(): Boolean {return true}override fun getAccountId(): String {return "这是来自usercenter的召唤"}override fun getUserFragment(activity: Activity): BaseFragment? {return UserFragment()}}
三:ServiceFactory
/*** author : Naruto* date : 2019-09-07* desc : ServiceFactory,对外提供设置和获取IAccountService的具体实现类* version:*/
class ServiceFactory private constructor() {companion object {val instance: ServiceFactory by lazy {ServiceFactory()}}private var accountService: IAccountService? = nullpublic fun setAccountService(service: IAccountService) {this.accountService = service}public fun getAccountService(): IAccountService {if (accountService == null) {accountService = EmptyAccountService()}return this.accountService!!}}
四:
/*** author : Naruto* date : 2019-09-07* desc :* version:*/
class UserCenterApplication : BaseModuleApplication() {private val TAG = "UserCenterApplication"override fun initModuleApplication() {ServiceFactory.instance.setAccountService(AccountService())Log.e(TAG, "UserCenterApplication-initModuleApplication")}override fun initModuleData() {Log.e(TAG, "UserCenterApplication-initModuleData")}}
五:使用toast(ServiceFactory.instance.getAccountService().getAccountId())
这样引申出一个问题:Application的动态配置
当用户模块单独调试的时候,UserApplication需要单独初始化。当模块集中调试的时候,APP的的Application就需要对所有的模块application进行初始化。what should i do?
我们可以采用反射的方式来实现模块的Application初始化。
(1):在Base模块,定义BaseModuleApplication,里面定义了两个方法,initModeApp 是初始化当前模块时需要调用的方法,initModuleData 是所有模块的都初始化后再调用的方法。/*** author : Naruto* date : 2019-09-07* desc :* version:*/
abstract class BaseModuleApplication : BaseApplication() {override fun onCreate() {super.onCreate()initModuleApplication()initModuleData()}/*** 初始化模块的Application*/public abstract fun initModuleApplication()/*** 所有组件的都初始化后再调用的方法*/public abstract fun initModuleData()
}(2):所有的Application都继承BaseModuleApplication,然后实现方法。/*** author : Naruto* date : 2019-09-07* desc :* version:*/
class UserCenterApplication : BaseModuleApplication() {private val TAG = "UserCenterApplication"override fun initModuleApplication() {ServiceFactory.instance.setAccountService(AccountService())Log.e(TAG, "UserCenterApplication-initModuleApplication")}override fun initModuleData() {Log.e(TAG, "UserCenterApplication-initModuleData")}}(3):在Base模块中,定义ApplicationConfig,定义一个数组,我们把需要初始化的模块application的完整类名放到数组中。
class ApplicationConfig {companion object {private const val UserCenterApplication: String = "com.zx.user.UserCenterApplication"private const val MsgApplication: String = "com.message.MsgApplication"val moduleApps = listOf(UserCenterApplication,MsgApplication)}}(4):主Application的initModuleApplication,遍历数组,通过反射的方式初始化各个application。
/*** author : Naruto* date : 2019-09-07* desc :* version:*/
class MainApplication : BaseModuleApplication() {override fun initModuleApplication() {try {val moduleApps = ApplicationConfig.moduleAppsfor (moduleApp in moduleApps) {val clazz = Class.forName(moduleApp)val instance = clazz.newInstance() as BaseModuleApplicationinstance.initModuleApplication()}} catch (e: Exception) {e.printStackTrace()}}override fun initModuleData() {try {val moduleApps = ApplicationConfig.moduleAppsfor (moduleApp in moduleApps) {val clazz = Class.forName(moduleApp)val instance = clazz.newInstance() as BaseModuleApplicationinstance.initModuleData()}} catch (e: Exception) {e.printStackTrace()}}}
2.4:question three:组件之间的页面跳转
这里采用阿里开源的ARouter。ARouter是阿里巴巴开源路由框架,主要解决组件间、模块间的界面跳转问题。
https://blog.csdn.net/weixin_37292229/article/details/93375669
2.5:集成调试
在主模块的build.gradle中配置简短的代码就ok了。
if (isUserModule.toBoolean()) {
implementation project(':UserCenter')
}
本文中的模块化开发,告一段落。
Finally, I think a meaningful life is to insist on doing something embarrassing.
Come on (ง • ̀ _ •) ง Naruto
Android模块化和组件化开发相关推荐
- 对前端工程化、模块化、组件化开发的理解
参考理解一: 提到前端往往很多人的映像就是入门简单,HTML.CSS加一起一个星期基本上就能大概上手,JS难一点但也能很快写一些简单的小效果,在网上随便一搜索各种特效代码随意用,一个新手前端也能在很短 ...
- 前端模块化、组件化开发
使用过ReactJS进行Web UI的组件化开发,和使用过AngularJS的双向数据绑定和模块化后,感觉到了组件化.模块化.双向数据绑定对Web前端开发的重要性. 1.组件化可以极大提高前端代码的可 ...
- Android 开发:由模块化到组件化(一)
在Android SDK一文中,我们谈到模块化和组件化,现在我们来聊聊组件化开发背后的哪些事.最早是在广告SDK中应用组件化,但是同样适用于普通应用开发 以下高能,请做好心理准备,看不懂请发私信来交流 ...
- [Android Pro] 由模块化到组件化(一)
cp from : https://blog.csdn.net/dd864140130/article/details/53645290 在Android SDK一文中,我们谈到模块化和组件化,现在我 ...
- 工程化,模块化,组件化,规范化
前端讲究 工程化,模块化,组件化,层层递进. 一.工程化 工程化是整个工程的结构.样式和动作分离,工程化是一种思想而不是某种技术(当然为了实现工程化我们会用一些技术).各种规范.技术选型.项目构建优化 ...
- 前端工程化、模块化、组件化
工程化 前端工程化是一种高层次思想而不是某种技术,所谓前端工程化就是将前端项目当成一项系统工程进行分析.组织和构建从而达到项目结构清晰.分工明确.团队配合默契.开发效率提高的目的.而模块化和组 ...
- 前端模块与组件、模块化与组件化编程
文章目录 前言 1.前端模块化 2.前端组件化 一.模块与组件的理解,存在的意义以及作用 1.模块 2.组件---实现应用中局部功能代码和资源的集合 2.1 单文件组件与非单文件组件 二.模块化与组件 ...
- 什么是前端模块化,组件化,工程化?
1.前端模块化: 可以理解为一组自定义业务的抽象封装,是根据项目的情况来进行封装组合到一起的,比如我们可以分为登录模块,评论模块.模块可维护性好,组合灵活,方便调用,多人协作互不干扰. 2.前端组件化 ...
- 架构:Android 组件化开发
前言 强烈推荐先阅读这篇文章 Android 组件化最佳实践 本文是阅读实践后的思考总结,更倾向实践步骤. 组件化开发架构 组件化开发大体就是这样的架构,最关键的是base 和 base_custom ...
最新文章
- 你有哪些deep learning(rnn、cnn)调参的经验?
- ubuntu下 apache phpmyadmin 的安装和使用
- SQL性能优化整合持续更新
- linux上开发应用程序_如何在Linux上安装软件应用程序
- 电脑重启f12怎么处理_电脑开机按f12怎么恢复系统(详解f12的使用方法)
- [文摘]Eclipse中如何批量替换
- 两个iOS应用之间的跳转
- oracle ebs工单入库,ORACLE-EBS_库存功能点操作模块.doc
- Mybatis工作中常用动态SQL总结
- excel 第六次人口普查_第六次全国人口普查表短表(标准版)
- python docx 删除表格
- 2022淘宝618超级喵运会怎么玩?2022淘宝618喵运会玩法技巧
- android txt操作,android txt文件保存读取操作
- C盘无法扩展卷(因后面有个恢复分区)——删除恢复分区
- gis怎么改鼠标滚轮缩放_【精华】ArcGIS鼠标滚轮
- 程序猿转行为什么这么难
- 论文笔记之:Co-saliency Detection via A Self-paced Multiple-instance Learning Framework
- 5G NR PDSCH的相位跟踪参考信号PTRS
- 攻防世界 web高手进阶区 10分题 weiphp
- filebeat+redis+logstash+elasticsearch filebeat+kafka+zookeeper+logstash+elasticsearch