组件化模块化
[TOC]
在移动应用上由于应用本身与使用者相贴近,日常开发中难免的需求变更朝令夕改、朝三暮四,尤其遇到没啥规范流程的或者形式主义流程;
关于组件化模块化是什么及其优点不再赘述,在此补充点优点而已:减少名言的联想
Linus:Read the fucking source code
我们的终极目标不仅是解耦等。简化、轻量化框架,减少过分约束而给予组件/模块内充分的自由,从初始设计已有两年余,由于重复搬砖没得时间记录,
文章中尽量不贴fucking code,有良好的思路大家都会有很好合适自身需求的实现。
组件 模块
鉴于网上很多文章对于组件和模块的定义众说纷纭,再次声明本文定义,参考资料来源维基百科
基于组件的软件工程(Component-based software engineering,简称CBSE)或基于组件的开发(Component-Based Development,简称CBD**)是一种软件开发范型。它是现今软件复用理论实用化的研究热点,在组件对象模型的支持下,通过复用已有的构件,软件开发者可以“即插即用”地快速构造应用软件。这样不仅可以节省时间和经费,提高工作效率,而且可以产生更加规范、更加可靠的应用软件
模块 是指由数个基础功能组件组成的特定功能组件,可用来组成具完整功能之系统、设备或程序。模块通常都会具有相同的制程或逻辑,更改其组成组件可调适其功能或用途。
综上组件Component是一种工具功能性质,而模块Module具有系统功能性质。例如jetpack中的构架组件.
模型model与模块还是区分对待。
由简单到复杂
长 短之相形,难 易之相成
任何系统都是由简单到复杂逐渐演化构成。类似于生态系统。稳定而强大的系统均是由简单的逐渐进化为复杂的系统。简单系统需要具备可进化性,其高一级系统需要有可退化性。而进化的必要因素时间
从AndroidX JetPack开始,构件一个兼具进化与退化的弹性系统框架。适应目的,分离表现层显示层,重复常用功能视图层操作形式已经定型的提取VM/模型组件,如视频播放 已知用户需求暂停,快进,声音,亮度;接口提供给了UI层,但UI层又要重新写SeekBar,Button 等UI控件,进一步看Seek Bar等也有自身的一些约定成俗的习惯性响应,这种VM组件是否可以直接包含这些UI控件,由视图层使用时传入,VM层仅仅与控件互动与Seek Bar的进度和与Button点击,而不关心UI层传入的是什么样子的控件,也不关心控件的位置,这些全都是UI层的事情。其实可以传入对应的接口控件,但当前控件没有进化到这一代。
Model模型层做提供实质性需求的业务。如视频播放,用什么播放器,自带的第三方的由mondel接管。用户需求是从视图层发起请求,VM层处理视图发起后的请求给Model去处理,Model处理后结果由VM层得知,VM又由更新数据去更新UI。
完成于此后。除非播放器更新换代,添加了其他功能(预览帧,GIF截取)VM,与M均不需要更新code.重复的搬砖仅仅是将UI搬运。
我们的组件化目标
首先肯定是解耦,防止代码污染;其次单模块调试,方便调试加快编译速度,提高专注效率;然后是框架轻量尽量不入侵,不过分限制模块,给模块内自由;能快速构建其一个基础功能齐全的Hello World;
最终效果
外核保护内核,仅暴露少量Base类接口,这些类的具体实现都在内核包中实现,可混淆后发布aar到项目私有maven,由开发版的外核配置依赖具体版本的内核;外核包中的少量类仅有及少量代码;
image image网络请求
//登录请求
private void click() {
getViewModel(LoginViewModel.class)
.sendAction(new RequestAction()
.setTipsArgs(new VmTipsArgs.Builder().tipMessage("请求失败了").build())).
doOnData((action, data) -> {
AppLog.d(TAG, "发起登录成功 doOnData1=", data);
showToast("登录成功1" + data);
})
.doOnData((action, data) -> {
AppLog.d(TAG, "发起登录成功 doOnData2=", data);
showToast("登录成功2" + data);
})
.doOnDone(action -> {
AppLog.d(TAG, "发起登录完成1");
showToast("登录结束");
})
.doOnListener(action -> {
AppLog.d(TAG, "开始登录 loading....");
showToast("loading....");
})
.doOnDone(action -> {
AppLog.d(TAG, "发起登录完成2");
})
.doOnError((action, e) -> {
AppLog.d(TAG, "登录失败");
})
;
}
日志
MainActivity doOnListener开始登录 loading....
MainActivity doOnData发起登录成功 doOnData1= "{uid:123}"
MainActivity doOnData发起登录成功 doOnData2= "{uid:123}"
MainActivity doOnDone发起登录完成1
MainActivity doOnDone发起登录完成2
组件化模块化需要解决的问题
-
组件隔离,模块独立,模块可单独调试;
每人只能看到框架代码和调试外壳代码,其他人的代码眼不见心不烦;(组件隔离:A组件的部分功能可抛出由其他组件B完成;模块独立:模块有自己的小生态,我在此为其添加统一的调试外壳,而不是变身app,浪费转换时间,也不需要写两份清单文件)
-
模块初始化注册【代码插桩;反射初始化等;ASM】推荐模块初始化注册插件
-
组件/模块之间的通讯,相互调用,数据传递【modular-event ,LiveData-Bus ,本地广播等】
-
组件/模块怎么通知其他组件响应某个事件(组件的视听功能)
-
模块界面之间的跳转,因为为了解耦,组件间不可以直接互相调用【ARouter等】
-
主项目获取并显示组件的fragment
-
组件间如何集成并调试
-
获取其他组件的数据或服务(发派信使携带任务,完成返回)
-
资源命名重复,资源本身重复冗余
-
组件之间避免过度依赖年轻的组件,基础组件避免依赖不成熟的第三方
-
其他...
举例包含其中3,4,5,6的一个业务场景:
多个模块中的UI需要组合显示在某同一个界面中,牵扯数据刷新,模块间数据传递,及相互调用等问题
image解决问题
-
问题1:
-
问题2:【掘金】Android组件化之组件/模块初始化注册到application;组件生命周期注册
...
未完待续...
网友评论