同层的其他模块,如何,能拿到ARouter的path?
同层的其他模块编译时,如何,共享AccountBean类、IAccountService接口?
这就是模块之间的编译隔离,带来的问题。
我们很自然的想到了framework模块,或者base层的其他模块。
我们只要将这些path定义、AccountBean类、IAccountService接口,下沉到base层,就可以实现编译上的代码共享。
如此一来,就带来了,另一个问题:代码的中心化问题。
2、代码的中心化
简单的path字符串定义,放在framework倒是还好。
如果所有business模块对外提供的接口和数据结构,都定义到framework的话,问题就有点严峻。
将会破坏:组件的 可替代性、可重用性、组件间耦合度
因为framework是基础模块嘛,所有business模块都依赖的模块,如此,不管你的business1模块是否依赖business2模块的对外接口,都会存在这一层依赖。
模块间的代码边界出现一些劣化。缺少了编译上的隔离。许多模块将会变得不够“独立”了。
可替代性、可重用性 越来越弱,想要替换或者复用某个business组件将变得越来越难。
将会导致,我们很难知道,哪些business对哪些business 接口有依赖。
同时,framework模块随着功能迭代,会不断膨胀。
这就是,中心化的问题。
于是我们很自然的想到了一个解决方案:
实现了另一种接口暴露的形式——“.api化”。
将 business模块 对外提供的接口单独抽到 business-api 模块中。其他依赖他的模块只需要依赖他的business-api即可。
这个方案如何实践下去呢?
微信的api化方案
微信团队出了一个很巧妙的方案,这个方案对android的组件化开发,产生了非常深远的影响。
后面很多做组件化开发的团队,在解决中心化问题基本都会用到类似的方案。
以下为,微信官方博客的原文引用:
使用方式和思路都很简单。对于java文件,将工程里想要暴露出去的接口类后缀名从“.java”改成“.api”,就可以了。
而且并不只是java文件,其他文件如果也想暴露,在文件名后增加".api”,也一样可以。
当然,要让工程支持这样的方式,gradle文件肯定会有一点改变。
它的实现原理也相当简单:自动生成一个“SDK”工程,拷贝.api后缀文件到工程中就行了,后面其他工程依赖编译的只是这个生成的工程。简单好用。
api方案有点类似于android的AIDL的思路。
微信API方案的变种
gradle 根据src/api文件来,自动生成{moduleName}-api模块。
如果,src/api文件不存在,将不会自动生成 {moduleName}-api 模块。
通过API模块来解决代码中心化问题带来的好处:
-
让各个business的之间的依赖明确
-
让business对外提供的接口明确。
从而加强了模块的:可替代性。
只要两个business对外提供的API一致,就可以相互替换。
3、单独编译、测试 business的单个模块
模块变多了,项目变大了,整个项目的编译速度变慢了。
业内有两种常用做法。
- 方案一:动态配置 build.gradle。
只要让单个的组建能编译成APP就能单独测试。
- 方案二:多壳APP
方案来自,在聚美优品。
这里需要注意:假如,Demo1是business1的壳APP。那么Demo1还需要依赖哪些businessXXX呢?
刚好,前面做的api化,能排上用场。
business1依赖的businessXXX-api模块对应的businessXXX模块,Demo1也需要依赖。
为甚?因为,business1依赖的businessXXX-api模块,意味着,business1需要依赖 businessXXX提供的功能,比如要跳转到businessXXX的activity?或者,要获取businessXXX的对象。
4、模块变多了,gradle代码同比增长,gradle 代码复用
在项目跟目录的build.gradle文件中配置Extra属性
如此可以实现统一管理版本号,和依赖。
但是,但是,但是,这个方案存在明显的缺陷。
-
不支持,自动补全
-
不支持Find Usages,查找所有应用的地方
- 使用时,不支持点击跳转
严重影响开发体验。
- 方案二:buildSrc
-
支持,自动补全
-
支持,Find Usages
-
支持,点击跳转
-
更完美的语法高亮
-
gradle文件复用
版本和依赖做到了统一管理,但是每个module都有各自的build.gradle,重复的build.gradle代码依然没有复用。
我们可以通过apply from:"xxx.gradle"的方式来复用gradle代码。
如下图
如上,我们可以在base.gradle中为每一个项目添加配置统一的编译逻辑,如:kotlin的支持,java版本的修改,maven库上场的逻辑等等
5、模块间:string、drawable、value、layout等,资源名冲突问题
如何防止资源名冲突?
比如businessA 和 businessB都在drawable目录下,都有一张同名的图片。
这两张图片只有一张会被打包到apk中,被使用。
这样就容易出现混乱。
这个问题比较好解决。让每个模块的资源名固定一个前缀。只要模块之间的前缀不一样就不会冲突。
gradle的resourcePrefix配置,刚好符合我们的需求。
如下配置,如果module中存在资源不以app_
开头,**lint走查会报warnning。**注意不会编译失败。
android {
resourcePrefix ‘app_’
}
如下截图的warning:
6、由于多module分层的项目结构,导致 R.class 冗余
可以通过booster的资源内联工具解决,R类的冗余。
详细可以自己查看booster官网,booster是didi开源的一个插件。booster.johnsonlee.io/feature/shr…
7、模块间,公共资源string、drawable、layout等如何共享?
没有找到很好的解决方案。
每个方案都有缺陷
比如说,business1和business2都要用到同一张图片。
那么这张图片该放到哪里呢?
- 1、把他放到api模块里来共享
资源这种,并非功能依赖,放到api模块也不太合适。
因为这样可能造成business1和business2模块原本没有关联也没有依赖;
但因为共用同一个资源,却导致存在了依赖。
- 2、在business1和business2中都放一个图片
如此会增大包体
- 3、在business1和business2中都放文件名同名的图片,让编译时资源合并的时候只使用同一张图片。
如此一来,放开各个模块资源命名,也容易导致开发时发生冲突。
自定义lint规则,让存在common和{moduleName}两种前缀?
- 4、将这张图片下沉到base层,如:framework模块,或者,单开一个lib-resource
如此一来,将会出现资源中心化问题。
上面的方法多少都有些缺陷,大叔还没有找到一个优雅的方式。如果你有什么好想法,一定要留言告诉大叔,大叔在此谢过你了。
8、各个business 模块 之间能不能有直接依赖?
千万不能这么操作。
假如:在 business/setting 中直接在gradle配置中依赖,business:account。
那么编译上的代码隔离就彻底被毁。就跟不要谈组件的可重用性、可替代性了。
implementation project(“:business:account”)
9、Application生命周期如何派发
各个组件如何获得Application.attach()、Application.onCreate()、Application.onTerminate()等的回调。
未完待续
10、组件生命周期管理
未完待续,待大叔踩过坑,实现了,再来写。
11、组件实现热插拔
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
总结:
面试是一个不断学习、不断自我提升的过程,有机会还是出去面面,至少能想到查漏补缺效果,而且有些知识点,可能你自以为知道,但让你说,并不一定能说得很好。
有些东西有压力才有动力,而学到的知识点,都是钱(因为技术人员大部分情况是根据你的能力来定级、来发薪水的),技多不压身。
附上我的面试各大专题整理: 面试指南,满满的都是干货,希望对大家有帮助!
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
但让你说,并不一定能说得很好。
有些东西有压力才有动力,而学到的知识点,都是钱(因为技术人员大部分情况是根据你的能力来定级、来发薪水的),技多不压身。
附上我的面试各大专题整理: 面试指南,满满的都是干货,希望对大家有帮助!
[外链图片转存中…(img-mM6Vusdk-1712148590568)]
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算