组件化框架 CC 的源码解读
2018-12-01 本文已影响92人
你可记得叫安可
概述
CC 框架是一个面向协议的组件化框架,相较于其他面向接口和数据结构的组件化框架(得到的框架等),面向协议的意思是通过开发者自己定义 ActionName 和数据 Map 等来进行调用。因此不需要开发者再重新定义清晰的接口,而是将这个调用转变为协议,因此能够提供跨平台的功能。
同步调用
CCResult result = CC.obtainBuilder(COMPONENT_NAME_A)
.setActionName("getInfo")
.build()
.call();
异步调用
CC.obtainBuilder("demo.lifecycle")
.build()
.callAsyncCallbackOnMainThread(printResultCallback);
调用时序图
点击查看原图,可看到清晰的时序图
代码依赖隔离
CC 通过编译的手段实现代码隔离。在主工程的 gradle 中,通过如下语句将各个组件编译进来:
addComponent 'demo_component_a'
addComponent 'demo_component_kt'
addComponent 'demo_component_jsbridge'
addComponent
是一个自定义的 lamda 表达式,源码在 cc-settings.gradle 中。
- 通过过滤筛选出
assemble
和install
的 task,表明此刻进行的 task 是生成 apk 的 task(而不是 sync 之类的) - 将
addComponent
替换为api
或compile
通过 addComponent
就实现了编写代码阶段不能随意使用其他模块的代码和资源,在编译时再换成依赖,实现代码隔离
编译时依赖注入
CC 通过编译的手段实现依赖注入。在主工程的 cc-settings-demo.gradle 中,通过如下语句将实例编译阶段注入:
ccregister.registerInfo.add([
//在自动注册组件的基础上增加:自动注册组件B的processor
'scanInterface' : 'com.billy.cc.demo.component.b.processor.IActionProcessor'
, 'codeInsertToClassName' : 'com.billy.cc.demo.component.b.ComponentB'
, 'codeInsertToMethodName' : 'initProcessors'
, 'registerMethodName' : 'add'
])
在 ComponentB
中我们可以看到:
private void initProcessors() {
}
private void add(IActionProcessor processor) {
map.put(processor.getActionName(), processor);
}
initProcessors()
方法中没有任何代码。add(IActionProcessor processor)
方法接收一个实现了 IActionProcessor
接口的实例。编译后的代码如下:
可以看到编译后,
initProcessors()
方法中注入了 add()
方法,并且传入了各个 Processor
的实例。
实践
我们可以运用代码隔离和依赖注入来实现模块的完全解耦。
- 所有模块相互之间不可见,编译 apk 时,才打包进 apk
- 编写代码阶段不可见的模块之间如何进行通信呢?在最底层模块实现一个类,像
ComponentB
中一样持有一个类名 - 实例
的 map。编写代码阶段,一个模块需要与另个一个模块通信时,就从这个 map 中取出另一个模块的 interface,面向接口进行通信。打包时,通过依赖注入将各个模块的实例加入到 map 中,这样运行时就是各个模块的实例了。