上一篇对整个框架结构进行了简单的介绍,本篇将较为细致的介绍下实现细节。
一、router_annotation模块主要有两个注解Route和Extra,以一个RouteMeta类;
Route注解用来声明路由路径,路径至少是两级,目的是为了将不同module的跳转路径分到不同的路由分组中:
//元注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface Route {
//路由的路径,标识一个路由节点
String path();
//将路由节点进行分组,可以实现按组动态加载
String group() default "";
}
Extra注解用来声明额外信息,实现数据或ISERVICE对象(自定义的接口)在模块间的传递:
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.CLASS)
public @interface Extra {
String name() default "";
}
RouteMeta用来保存路由信息,通过解析Route注解获取。路由页面有两种类型:1.Activity,代表需要路由的Activity;2.ISERVICE,代表可以传递的ISERVICE对象,实现了ISERVICE的接口,都可以通过路由来传递。
public class RouteMeta {
//路由页面的类型:Activity或者IService
public enum Type {
ACTIVITY,
ISERVICE
}
private Type type;
//节点 (Activity)
private Element element;
//注解使用的类对象
private Class destination;
//路由地址
private String path;
//路由分组
private String group;
...
}
注意:annotation模块与compiler模块的中文注释使用GBK格式,否则编译时会报错
二、router_compiler模块compiler模块使用Javax的Processor来处理注解,使用google的AutoService来自动编译Processor类,使用javapoet来生成Java类。Javax是Java的库,Android不支持,所以compiler模块是Java的library模块。
没用过javapoet的同学,可以参考https://github.com/square/javapoet。
1.添加配置使用前,需要先在compiler模块的build.gradle中导入框架:
apply plugin: 'java-library'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
compileOnly 'com.google.auto.service:auto-service:1.0-rc4'
implementation 'com.squareup:javapoet:1.11.1'
implementation project(':router_annotation')
}
// java控制台输出中文乱码
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
sourceCompatibility = "7"
targetCompatibility = "7"
2.处理Route注解
声明一个RouteProcessor继承Processor,用来处理Route注解。先给RouteProcessor添加注解,设置处理的参数:
//自动编译Processor类
@AutoService(Processor.class)
//处理器接收的参数 替代 {@link AbstractProcessor#getSupportedOptions()} 函数
@SupportedOptions(Consts.ARGUMENTS_NAME)
//指定使用的Java版本 替代 {@link AbstractProcessor#getSupportedSourceVersion()} 函数
@SupportedSourceVersion(SourceVersion.RELEASE_7)
//注册给哪些注解的 替代 {@link AbstractProcessor#getSupportedAnnotationTypes()} 函数
@SupportedAnnotationTypes({Consts.ANN_TYPE_ROUTE})
public class RouteProcessor extends AbstractProcessor {
然后,初始化RouteProcessor,从ProcessingEnvironment中获取需要的处理工具:
/**
* 初始化 从 {@link ProcessingEnvironment} 中获得一系列处理器工具
*
* @param processingEnvironment
*/
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
//获得apt的日志输出
log = Log.newLog(processingEnvironment.getMessager());
//获取节点
elementUtils = processingEnvironment.getElementUtils();
//获取类型
typeUtils = processingEnvironment.getTypeUtils();
//获取文件生成器
filerUtils = processingEnvironment.getFiler();
//参数是模块名 为了防止多模块/组件化开发的时候 生成相同的 xx$$ROOT$$文件
Map options = processingEnvironment.getOptions();
if (!Utils.isEmpty(options)) {
moduleName = options.get(Consts.ARGUMENTS_NAME);
}
log.i("RouteProcessor Parmaters:" + moduleName);
if (Utils.isEmpty(moduleName)) {
throw new RuntimeException("Not set Processor Parmaters.");
}
}
然后,在process方法(注解的处理方法)中遍历被Route注解的节点,先判断节点的类型,再使用RouteMeta保存节点信息,然后验证节点的路由地址是否符合规则,然后使用categories() 根据分组名来保存节点信息到groupMap中;
然后,遍历groupMap中的节点信息,使用javapoet工具,根据分组名生成一个继承IRouteGroup接口的Java类,叫做分组信息类,用来保存每个分组的路由信息,比如:
public class DNRouter$$Group$$main implements IRouteGroup {
@Override
public void loadInto(Map atlas) {
atlas.put("/main/test", RouteMeta.build(RouteMeta.Type.ACTIVITY,SecondActivity.class, "/main/test", "main"));
atlas.put("/main/service1", RouteMeta.build(RouteMeta.Type.ISERVICE,TestServiceImpl1.class, "/main/service1", "main"));
atlas.put("/main/service2", RouteMeta.build(RouteMeta.Type.ISERVICE,TestServiceImpl2.class, "/main/service2", "main"));
}
}
注意:不同的模块,不能使用相同的分组名。因为相同的分组名会生成相同的分组信息类,打包成APK时只保留一个。
然后,遍历所有的分组信息类,使用javapoet工具,根据模块名生成一个继承IRouteRoot接口的Java类,叫做表信息类,用来保存所有的分组信息类,比如:
public class DNRouter$$Group$$module1 implements IRouteGroup {
@Override
public void loadInto(Map atlas) {
atlas.put("/module1/test", RouteMeta.build(RouteMeta.Type.ACTIVITY,Module1Activity.class, "/module1/test", "module1"));
atlas.put("/module1/service", RouteMeta.build(RouteMeta.Type.ISERVICE,TestServiceImpl.class, "/module1/service", "module1"));
}
}
处理Route注解的生成类,到这里,Route注解就处理玩了。
3.处理Extra注解声明一个ExtraProcessor继承Processor,用来处理Extra注解。基本流程与RouteProcessor一致,需要注意的是
Route注解只支持Activity和IService两种类型,Extra注解支持更多的类型,包括基本类型、数组、String、Object等,所以需要做更多的类型判断:
if (type == TypeKind.BOOLEAN.ordinal()) {
statement += "getBooleanExtra($S, " + defaultValue + ")";
} else if (type == TypeKind.BYTE.ordinal()) {
statement += "getByteExtra($S, " + defaultValue + ")";
} else if (type == TypeKind.SHORT.ordinal()) {
statement += "getShortExtra($S, " + defaultValue + ")";
} else if (type == TypeKind.INT.ordinal()) {
statement += "getIntExtra($S, " + defaultValue + ")";
} else if (type == TypeKind.LONG.ordinal()) {
statement += "getLongExtra($S, " + defaultValue + ")";
} else if (type == TypeKind.CHAR.ordinal()) {
statement += "getCharExtra($S, " + defaultValue + ")";
} else if (type == TypeKind.FLOAT.ordinal()) {
statement += "getFloatExtra($S, " + defaultValue + ")";
} else if (type == TypeKind.DOUBLE.ordinal()) {
statement += "getDoubleExtra($S, " + defaultValue + ")";
} else {
//数组类型
if (type == TypeKind.ARRAY.ordinal()) {
addArrayStatement(statement, fieldName, extraName, typeMirror, element);
} else {
//Object
addObjectStatement(statement, fieldName, extraName, typeMirror, element);
}
return;
}
然后根据类名+$$Extra
,使用javapoet生成一个继承IExtra的Extra信息类,用来给添加了Extra注解的成员变量复制,例如:
public class Module2Activity$$Extra implements IExtra {
@Override
public void loadExtra(Object target) {
Module2Activity t = (Module2Activity)target;
t.msg = t.getIntent().getStringExtra("msg");
}
}
如果使用Extra注解的成员变量是TestService类型(自定义的接口,用来传递对象),并且Extra注解中设置了路由路径,则会生成下面的类:
public class SecondActivity$$Extra implements IExtra {
@Override
public void loadExtra(Object target) {
SecondActivity t = (SecondActivity)target;
t.a = t.getIntent().getStringExtra("a");
t.b = t.getIntent().getIntExtra("b", t.b);
t.c = t.getIntent().getShortExtra("c", t.c);
t.d = t.getIntent().getLongExtra("d", t.d);
t.e = t.getIntent().getFloatExtra("e", t.e);
t.f = t.getIntent().getDoubleExtra("f", t.f);
t.g = t.getIntent().getByteExtra("g", t.g);
t.h = t.getIntent().getBooleanExtra("h", t.h);
t.i = t.getIntent().getCharExtra("i", t.i);
t.aa = t.getIntent().getStringArrayExtra("aa");
t.bb = t.getIntent().getIntArrayExtra("bb");
t.cc = t.getIntent().getShortArrayExtra("cc");
t.dd = t.getIntent().getLongArrayExtra("dd");
t.ee = t.getIntent().getFloatArrayExtra("ee");
t.ff = t.getIntent().getDoubleArrayExtra("ff");
t.gg = t.getIntent().getByteArrayExtra("gg");
t.hh = t.getIntent().getBooleanArrayExtra("hh");
t.ii = t.getIntent().getCharArrayExtra("ii");
t.j = t.getIntent().getParcelableExtra("j");
Parcelable[] jj = t.getIntent().getParcelableArrayExtra("jj");
if( null != jj) {
t.jj = new TestParcelable[jj.length];
for (int i = 0; i < jj.length; i++) {
t.jj[i] = (TestParcelable)jj[i];
}
}
t.k1 = t.getIntent().getParcelableArrayListExtra("k1");
t.k2 = t.getIntent().getParcelableArrayListExtra("k2");
t.k3 = t.getIntent().getStringArrayListExtra("k3");
t.k4 = t.getIntent().getIntegerArrayListExtra("k4");
t.test = t.getIntent().getIntExtra("hhhhhh", t.test);
t.testService1 = (TestService) DNRouter.getInstance().build("/main/service1").navigation();
t.testService2 = (TestService) DNRouter.getInstance().build("/main/service2").navigation();
t.testService3 = (TestService) DNRouter.getInstance().build("/module1/service").navigation();
t.testService4 = (TestService) DNRouter.getInstance().build("/module2/service").navigation();
}
}
处理Extra注解的生成类,都放在com.example.dn_component下
三、router_core模块router_core模块是用来实现跳转逻辑的。
1.初始化在Application中进行初始化,加载表信息类。
先定义一个路由表Warehouse,来保存所有的路由信息。
public class Warehouse {
// root 映射表 保存分组信信息类
static Map
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?