背景
公司之前模块化开发中,使用了AutoRegister作为自动注册组件方案,且ARouter中也使用了AutoRegiser
主要原理
在编译时,扫描即将打包到apk中的所有类,将所有组件类收集起来,通过修改字节码的方式生成注册代码到组件管理类中,从而实现编译时自动注册的功能,不用再关心项目中有哪些组件类了。
特点
不需要注解,不会增加新的类;性能高,不需要反射,运行时直接调用组件的构造方法;能扫描到所有类,不会出现遗漏;支持分级按需加载功能的实现。
使用
名词介绍
scanInterface : (必须)字符串,接口名(完整类名),所有直接实现此接口的类将会被收集
codeInsertToClassName : (必须)字符串,类名(完整类名),通过编译时生成代码的方式将收集到的类注册到此类的codeInsertToMethodName方法中
codeInsertToMethodName: 字符串,方法名,注册代码将插入到此方法中。若未指定,则默认为static块,(方法名为:)
registerMethodName : (必须)字符串,方法名,静态方法,方法的参数为 scanInterface
scanSuperClasses : 字符串或字符串数组,类名(完整类名),所有直接继承此类的子类将会被收集
include : 数组,需要扫描的类(正则表达式,包分隔符用/代替,如: com/billy/android/.),默认为所有的类
exclude : 数组,不需要扫描的类(正则表达式,包分隔符用/代替,如: com/billy/android/.),
在对应的module的gradle中
都需要添加
apply plugin: 'auto-register'
在app module中添加
project.ext.registerInfoList = [
[
'scanInterface' : 'com.billy.app_lib_interface.ICategory'
// scanSuperClasses 会自动被加入到exclude中,下面的exclude只作为演示,其实可以不用手动添加
, 'scanSuperClasses' : ['com.billy.android.autoregister.demo.BaseCategory']
, 'codeInsertToClassName' : 'com.billy.app_lib_interface.CategoryManager'
//未指定codeInsertToMethodName,默认插入到static块中,故此处register必须为static方法
, 'registerMethodName' : 'register' //
, 'exclude' : [
//排除的类,支持正则表达式(包分隔符需要用/表示,不能用.)
'com.billy.android.autoregister.demo.BaseCategory'.replaceAll('\\.', '/') //排除这个基类
]
] , [
'scanInterface' : 'com.billy.app_lib.IOther'
, 'codeInsertToClassName' : 'com.billy.app_lib.OtherManager'
, 'codeInsertToMethodName' : 'init' //非static方法
, 'registerMethodName' : 'registerOther' //非static方法
],
第一个注册中插入到static必须提供static方法注册
static void register(ICategory category) {
if (category != null) {
CATEGORIES.put(category.getName(), category);
}
}
在第一个注册中实现中会自动插入以下代码
public class CategoryManager {
static
{
CategoryManager.register(new CategoryA()); //scanInterface的实现类
CategoryManager.register(new CategoryB()); //scanSuperClasses的子类
}
}
在第二个注册中,指定了codeInsertToMethodName,会在init()方法中调用registerOther方法,完成实现类注册
public OtherManager() {
init();
}
private void init () {
}
private void registerOther(IOther other) {
if (other != null) {
LIST.add(other);
}
}
在module之间的调用中,可以通过moduleManger的list或者map获取到需要的已经注册的module实例,类似调用module的public方法即可
CategoryB categoryB= (CategoryB) CategoryManager.getCategory("CategoryB");
if (categoryB!=null){
categoryB.doSth();
}