完全组件化框架Atoms-mvp

image

前言

前一段时间看到JessYan的一篇文章,分享他的MVP开源框架,我相信大多数人应该都还有印象,不得不说这个框架确实很棒,感谢JessYan的开源和分享。框架虽然不是项目的核心,但却是项目的基础。一个好的项目框架,能帮助你快速地开始企业级项目开发。本人经过对MVPArms的研究考量并结合自己的想法与实际开发过程得到Atoms-MVP。

项目已开源Github,完全组件化的项目框架Atoms-mvp

什么是组件化

组件化就是将一个完整的App按照关注点分离成多个组件,使得每个组件成为单独的个体,做到组件内部的高聚合和组件之间低耦合。

为什么我们要组件化?

宏观上讲,组件化使开发人员更加专注于各模块的开发,使团队成员更加方便迭代升级和维护,管理者也更容易统筹帷幄,规范项目层次和结构统一。微观上讲,组件化必将对基础库下沉从而提高复用,这也是项目框架演变进化过程中的的核心思想,对于子模块一个萝卜一个坑,互相不直接依赖,所以不用担心变更带来的风险。从根本上避免一个小小的改动牵连多处需要修改,导致回归整个App测试。对于测试同学而言,能有效的减少测试的时间,原有的业务不需要再次进行功能测试,只需专注于发生变化的业务,以及最终的集成测试即可

Atoms-mvp组件化过程

1.面向开发过程,维护成本,学习成本。化繁为简,less is more,高扩展性为宗旨,使新手也能快速搭建自己的组件化项目

2.基础库下沉,只下沉最核心最必须,绝不拖泥带水,纳污藏秽。

2.弱化了Dagger2的使用频率,因为这对于一些新手来说Dagger2可能不是很好理解,排错不是很好,但是对于一些频繁使用到的Dagger代码我做了优化,省去了大量重复代码,帮助团队加快开发速度。

3.网络请求方面使用Rxjava,okhttp,retrofit组合式框架但是并没有使用RxCache处理缓存,因为我觉得这样会加重开发成本,增加编码量和维护成本,其次Okhttp本身是自带缓存策略的,我们可以到后期真正需要的时候再使用缓存框架

4.在设计架构时,将最原始,最需要,最重要的库打入baseLib封装成基础库,比如网络,support,依赖注入型框架dagger,以及和view相关的butterknife,或者其他的一些基础库,开发者可以自行扩展。目的是将这些充斥于整个界面相关的业务逻辑集成到最底层。往上一层封装整个APP需要的公共服务。其中包括CommonSDK用来承上启下,并提供ARouter路由框架,或者使用360Replugin插件化框架,为组件之间解耦做铺垫,开发者可视情况而定二选其一。以及业务服务库和公共UI库,统一整个APP的UI风格方便后期统一调整。再往上就是App的核心组件,各组件依赖公共层,组件之间绝对分离。最后整合在一起完美融合,形成一个APP应用系统

image

本项目特点

1.支持路由框架和插件划框架比如Arouter,RePlugin等

2.动态代理Application生命周期,各组件可做具体实现,使得子Module间接地拥有Application,能够在子module中初始化相对当前nodule的的第三方库。

3.各模块可配置单独的ServiceApi,拥有属于自己独立的Api接口,同时还支持不同host场景

4.各组件数据传输面向接口不直接依赖于对象,使组件化解耦更彻底,做到完全组件化。在下面我会一一讲到。

组件化的关键点

代码隔离

代码隔离同样也是代码解耦,每个组件之间代码互不侵入,互不依赖,团队之间应具备规范的意识。除了人为上的约束,IDE工具gradle也为我们提供了很好的代码隔离语法,从AS3.0开始类库依赖出现了四种新语法如下:

image

implementation:对应以前的compile。与compile的区别在于使用implementation在编译期间只对当前宿主可见,对其他宿主隔离。同时它还有一个好处是能够加快编译速度。打个比方如果宿主使用implementation引用库的话,当宿主发生变化重新编译时,库不需要再编译,只需要编译这个宿主。而如果你使用的是compile引用库的话,那么两者都需要重新编译。两者相比较推荐使用implementation。
compileOnly:这个语法就很有意思了,它的作用是依赖的类库只参与编译,而不会打包进Apk。应用场景:子Module中引入于父亲Module相同的库可使用compileOnly ,比如下面这个例子

子Module

  compileOnly "com.alibaba:arouter-compiler:1.1.4"
  compileOnly "com.jakewharton:butterknife-compiler:8.8.1"
  compileOnly  'com.google.dagger:dagger-compiler:2.15'

父Module

 api "com.alibaba:arouter-api:1.1.4"
 api "com.jakewharton:butterknife:8.8.1"
 api "com.google.dagger:dagger:2.15"

注意,如果你引入进来的是一个Module那么请注意父Module也应该有相同的引入,但是你不能调用这个Module的资源文件,否则编译运运行的时候会报错。如果您在其他模块以compile的方式依赖了相同lib,最终在打包过程中可能会出现重复代码,建议您采用compileOnly解决重复依赖的问题

runtimeOnly: 从上图可以看出,在代码隔离效果上,runtimeOnly的效果是最好的!在引用子模块最好选择runtimeOnly,防止主Module调用子Module的代码和资源。

其次我再补充说明一下资源文件隔离。虽然上面解决了代码隔离但是对于资源文件并没有控制,其他宿主还是能够访问下级的资源文件,为了避免编译时冲突,可为资源名增加一个前缀,约束资源文件的命名规范。

android {
    resourcePrefix "gank_" //给 Module 内的资源名增加前缀, 避免资源名冲突
}

独立的ServiceAPI

有些项目可能有多baseUrl的需求,这种情况Retrofit官方给了两种解决方案,如下。

第一种:在 @Get , @Post注解中不仅可以传相对路径,还可以传全路径

image

第二种:将全路径以参数@Url的形式传递给接口

image

独立的Application

对于有些子模块来说,它有属于自己依赖的第三方库,有些第三方库需要在Application中初始化,而一个应用程序的Application对象只有一个,每个组件又全部分离出去了,那么如何才能各组件共享?在Atoms-MVP中提供了解决方案。通过代理方式,委派一个AppDelegate对象去代理Application的生命周期。各各子模块只需在Manifest文件中定义 meta标签,指定真实被调用的Application生命周期类名,由Appdelegate创建时通过反射的手段初始化。贴一张图方便理解

image

数据传递

在组件化项目中,每个组件都是相对独立,那么他们之间如何进行数据传递呢?首先想到的是Intent、sp、file、广播、内容提供者等这些常见的数据传递方式,但是刚刚说了组件之间是相对独立的,不能直接把实体类传递过去,因为在完全解耦的组件化项目中,实体类不会下沉放到公共库,也不会在多个组件之间存在依赖关系,只出现在于属于它们自己的组件当中。那么如何将实体类也完全解耦呢?Atoms-mvp提供了一套解决方案,每个组件如果需要对外提供数据传递,那么统一在CommonService组件中声明向外提供服务接口,具体的实现由需要传递数据的组件负责,数据接收者只需要声明这个接口,再调用接口中定义的方法获取数据就能完成跨模块之间的数据传递。这样做使得组件之间不直接指引,避免各组件之间的类出现互相指引的关系,把原有的一对多的依赖变成了一对一的依赖,CommonService相当于一个中介者,来处理各组件之间需要交流的角色。另一方面这是一种很好的思想,想像一下如果没有中间件,那各组件之间数据传递相互指引很有可能就会出现相互缠绕导致耦合严重,一处修改,多出受灾。中间件的好处能够降低变更带来的风险,定义好通信协议,由组件实现或调用。大多数情况下变更的总是实现,接口相对很少变更,即使变更也有办法兼容。所以它能够对抗业务逻辑发生变化带来的风险。

总结

Android应用的架构,根据不同的应用场景和复杂程度使得技术架构也有不同,架构没有好坏之分,只要适用于自己的业务就是好架构,每一次的重构每一次的更新都是为了节省人力和成本,提高开发效率。如果您正打算使用组件化框架完全可以把我的项目搬过去,改一改包名即可。同时Atoms-mvp也可以作为大家在进行组件化时的参考资料,如果您觉得我的文章写的不错,对您有帮助请为我点赞。

Atoms-mvp项目地址:https://github.com/xwc520/Atoms-mvp


参考文档:

https://www.jianshu.com/p/1c5afe686d75

https://www.jianshu.com/p/f671dd76868f

关于我Vea

简书:https://www.jianshu.com/u/9184fed0c6f2

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,900评论 25 707
  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    阳明先生_X自主阅读 15,973评论 3 119
  • 今天我们聊一下罗伯特清奇说的关于你要进入右侧象限,成为企业拥有人的三个途径,进入b象限要记住你的目标是拥有一个系统...
    听雨廖哥阅读 1,384评论 0 0
  • “看—那天空,多像夕阳。一个鲜血染成的夕阳。看呀—”我是多么想对旁边的人道出这些词,如果,有人的话。 这是...
    星奏之歌阅读 202评论 0 0
  • 在雨中,我逢着一只毛发被淋湿的小猫 它黑亮的眼睛望着我 那么无助 那斑点尘埃的砖墙下 它更加瘦小 彳亍 中,我看见...
    梁熹光阅读 162评论 4 3