CountDownLatch的使用!系统里面经常用到!
跳转遇到的问题?Arounter需要解决的问题
不能拿到对方的类。你只能通过找到类的路径去反射拿到这个class,那么有没有一种更好的解决办法呢?
Arounter的原理:产生路由表,通过key去找到value
分析:
首先第一步,定义注解:
Target:ElementType.Type
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface Route {
/**
- 路由的路径 * * @return
/
String path(); /* - 将路由节点进行分组,可以实现动态加载 * * @return
*/
String group() default ""; }
</pre>
为什么需要分组?
Route注解里有path和group,这便是仿照ARouter对路由进行分组。因为当项目变得越来越庞大的时候,为了便于管理和减小首次加载路由表过于耗时的问题
第二步:定义基本的接口
**[图片上传失败...(image-c9e97f-1640330005823)]
IRouteGroup:自定义加载接口。不是自动生成的,自定义的
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">public interface IRouteGroup {
void loadInto(Map<String, RouteMeta> atlas); }</pre>**
第三步,编写注解处理器。
需要生成的.java文件
[图片上传失败...(image-11f849-1640330005863)]
EaseRouter_Root_app.java: 里面需要是代表有几个模块,组。有2组
EaseRouter_Group_main.java :包含了Main模块里面的跳转
EaseRouter_Group_show.java :包含了show模块里面的跳转
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">public class EaseRouter_Root_app implements IRouteRoot {
@Override
public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
routes.put("main", EaseRouter_Group_main.class);
routes.put("show", EaseRouter_Group_show.class);
}
}
</pre>
EaseRouter_Group_main.java文件
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">public class EaseRouter_Group_main implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put("/main/main",RouteMeta.build(RouteMeta.Type.ACTIVITY,MainActivity.class,"/main/main","main"));
atlas.put("/main/main2",RouteMeta.build(RouteMeta.Type.ACTIVITY,Main2Activity.class,"/main/main2","main"));
}
}</pre>
EaseRouter_Group_show
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">public class EaseRouter_Group_show implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put("/show/info",RouteMeta.build(RouteMeta.Type.ACTIVITY,ShowActivity.class,"/show/info","show"));
}
}</pre>
通过注解的形式重写几个方法,比butterknife的又强了点!
@AutoService(Processor.class)
/**
处理器接收的参数 替代 {@link AbstractProcessor#getSupportedOptions()} 函数
*/
@SupportedOptions(Constant.ARGUMENTS_NAME)
/**
* 注册给哪些注解的 替代 {@link AbstractProcessor#getSupportedAnnotationTypes()} 函数
*/
@SupportedAnnotationTypes(Constant.ANNOTATION_TYPE_ROUTE)
生成文件的方法:
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">/**
- @param set 使用了支持处理注解的节点集合
- @param roundEnvironment 表示当前或是之前的运行环境,可以通过该对象查找找到的注解。
- @return true 表示后续处理器不会再处理(已经处理)
*/ @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
if (!Utils.isEmpty(set)) {
//被Route注解的节点集合
Set<? extends Element> rootElements = roundEnvironment.getElementsAnnotatedWith(Route.class);
if (!Utils.isEmpty(rootElements)) {
processorRoute(rootElements);
}
return true;
}
return false; }
private void processorRoute(Set<? extends Element> rootElements) {
//获得Activity这个类的节点信息
TypeElement activity = elementUtils.getTypeElement(Constant.ACTIVITY);
TypeElement service = elementUtils.getTypeElement(Constant.ISERVICE);
for (Element element : rootElements) {
RouteMeta routeMeta;
//类信息
TypeMirror typeMirror = element.asType();
log.i("Route class:" + typeMirror.toString());
Route route = element.getAnnotation(Route.class);
if (typeUtils.isSubtype(typeMirror, activity.asType())) {
routeMeta = new RouteMeta(RouteMeta.Type.ACTIVITY, route, element);
} else if (typeUtils.isSubtype(typeMirror, service.asType())) {
routeMeta = new RouteMeta(RouteMeta.Type.ISERVICE, route, element);
} else {
throw new RuntimeException("Just support Activity or IService Route: " + element);
}
categories(routeMeta);
}
TypeElement iRouteGroup = elementUtils.getTypeElement(Constant.IROUTE_GROUP);
TypeElement iRouteRoot = elementUtils.getTypeElement(Constant.IROUTE_ROOT); //生成Group记录分组表
generatedGroup(iRouteGroup); //生成Root类 作用:记录<分组,对应的Group类>
generatedRoot(iRouteRoot, iRouteGroup); }</pre>
用2个Map保存信息!
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">/**
- key:组名 value:类名 / private Map<String, String> rootMap = new TreeMap<>(); /*
- 分组 key:组名 value:对应组的路由信息 */ private Map<String, List<RouteMeta>> groupMap = new HashMap<>();</pre>
生成Group的java文件
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">private void generatedGroup(TypeElement iRouteGroup) {
//创建参数类型 Map<String, RouteMeta>
ParameterizedTypeName parameterizedTypeName = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(String.class),
ClassName.get(RouteMeta.class));
ParameterSpec altas = ParameterSpec.builder(parameterizedTypeName, "atlas").build(); for (Map.Entry<String, List<RouteMeta>> entry : groupMap.entrySet()) {
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(Constant.METHOD_LOAD_INTO)
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.addParameter(altas); String groupName = entry.getKey();
List<RouteMeta> groupData = entry.getValue();
for (RouteMeta routeMeta : groupData) {
//函数体的添加
methodBuilder.addStatement("atlas.put(T.build(L,S,$S))",
routeMeta.getPath(),
ClassName.get(RouteMeta.class),
ClassName.get(RouteMeta.Type.class),
routeMeta.getType(),
ClassName.get(((TypeElement) routeMeta.getElement())),
routeMeta.getPath(),
routeMeta.getGroup());
}
String groupClassName = Constant.NAME_OF_GROUP + groupName;
TypeSpec typeSpec = TypeSpec.classBuilder(groupClassName)
.addSuperinterface(ClassName.get(iRouteGroup))
.addModifiers(Modifier.PUBLIC)
.addMethod(methodBuilder.build())
.build();
JavaFile javaFile = JavaFile.builder(Constant.PACKAGE_OF_GENERATE_FILE, typeSpec).build();
try {
javaFile.writeTo(filerUtils);
} catch (IOException e) {
e.printStackTrace();
}
rootMap.put(groupName, groupClassName); }
}</pre>
几个类:
TypeElement:元素类型,比如activty,Service
TypeMirror: 类信息
注解处理器的源码:
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">@AutoService(Processor.class)
/**
处理器接收的参数 替代 {@link AbstractProcessor#getSupportedOptions()} 函数
/ @SupportedOptions(Constant.ARGUMENTS_NAME)
/*
- 指定使用的Java版本 替代 {@link AbstractProcessor#getSupportedSourceVersion()} 函数
/ @SupportedSourceVersion(SourceVersion.RELEASE_7)
/* - 注册给哪些注解的 替代 {@link AbstractProcessor#getSupportedAnnotationTypes()} 函数
*/ @SupportedAnnotationTypes(Constant.ANNOTATION_TYPE_ROUTE)
public class RouterProcessor extends AbstractProcessor {
/**
-
key:组名 value:类名 / private Map<String, String> rootMap = new TreeMap<>();
/* -
分组 key:组名 value:对应组的路由信息 / private Map<String, List<RouteMeta>> groupMap = new HashMap<>(); /*
-
节点工具类 (类、函数、属性都是节点) / private Elements elementUtils; /*
-
type(类信息)工具类 / private Types typeUtils; /*
-
文件生成器 类/资源 */ private Filer filerUtils; private String moduleName; private Log log; @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文件
Map<String, String> options = processingEnvironment.getOptions();
if (!Utils.isEmpty(options)) {
moduleName = options.get(Constant.ARGUMENTS_NAME);
}
if (Utils.isEmpty(moduleName)) {
throw new RuntimeException("Not set processor moudleName option !");
}
log.i("init RouterProcessor " + moduleName + " success !");
}/**
- @param set 使用了支持处理注解的节点集合
-
@param roundEnvironment 表示当前或是之前的运行环境,可以通过该对象查找找到的注解。
-
@return true 表示后续处理器不会再处理(已经处理)
*/ @Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
if (!Utils.isEmpty(set)) {
//被Route注解的节点集合
Set<? extends Element> rootElements = roundEnvironment.getElementsAnnotatedWith(Route.class);
if (!Utils.isEmpty(rootElements)) {
processorRoute(rootElements);
}
return true;
}
return false;
}private void processorRoute(Set<? extends Element> rootElements) {
//获得Activity这个类的节点信息
TypeElement activity = elementUtils.getTypeElement(Constant.ACTIVITY);
TypeElement service = elementUtils.getTypeElement(Constant.ISERVICE);
for (Element element : rootElements) {
RouteMeta routeMeta;
//类信息
TypeMirror typeMirror = element.asType();
log.i("Route class:" + typeMirror.toString());
Route route = element.getAnnotation(Route.class);
if (typeUtils.isSubtype(typeMirror, activity.asType())) {
routeMeta = new RouteMeta(RouteMeta.Type.ACTIVITY, route, element);
} else if (typeUtils.isSubtype(typeMirror, service.asType())) {
routeMeta = new RouteMeta(RouteMeta.Type.ISERVICE, route, element);
} else {
throw new RuntimeException("Just support Activity or IService Route: " + element);
}
categories(routeMeta);
}
TypeElement iRouteGroup = elementUtils.getTypeElement(Constant.IROUTE_GROUP);
TypeElement iRouteRoot = elementUtils.getTypeElement(Constant.IROUTE_ROOT); //生成Group记录分组表
generatedGroup(iRouteGroup); //生成Root类 作用:记录<分组,对应的Group类>
generatedRoot(iRouteRoot, iRouteGroup);
}/**
-
生成Root类 作用:记录<分组,对应的Group类>
-
@param iRouteRoot
-
@param iRouteGroup
*/
private void generatedRoot(TypeElement iRouteRoot, TypeElement iRouteGroup) {
//创建参数类型 Map<String,Class<? extends IRouteGroup>> routes>
//Wildcard 通配符 ParameterizedTypeName parameterizedTypeName = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(String.class),
ParameterizedTypeName.get(
ClassName.get(Class.class),
WildcardTypeName.subtypeOf(ClassName.get(iRouteGroup))
));
//参数 Map<String,Class<? extends IRouteGroup>> routes> routes
ParameterSpec parameter = ParameterSpec.builder(parameterizedTypeName, "routes").build();
//函数 public void loadInfo(Map<String,Class<? extends IRouteGroup>> routes> routes)
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(Constant.METHOD_LOAD_INTO)
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.addParameter(parameter);
//函数体
for (Map.Entry<String, String> entry : rootMap.entrySet()) {
methodBuilder.addStatement("routes.put(T.class)", entry.getKey(), ClassName.get(Constant.PACKAGE_OF_GENERATE_FILE, entry.getValue()));
}
//生成类
String className = Constant.NAME_OF_ROOT + moduleName;
TypeSpec typeSpec = TypeSpec.classBuilder(className)
.addSuperinterface(ClassName.get(iRouteRoot))
.addModifiers(Modifier.PUBLIC)
.addMethod(methodBuilder.build())
.build();
try {
JavaFile.builder(Constant.PACKAGE_OF_GENERATE_FILE, typeSpec).build().writeTo(filerUtils);
log.i("Generated RouteRoot:" + Constant.PACKAGE_OF_GENERATE_FILE + "." + className);
} catch (IOException e) {
e.printStackTrace();
}
}private void generatedGroup(TypeElement iRouteGroup) {
//创建参数类型 Map<String, RouteMeta>
ParameterizedTypeName parameterizedTypeName = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(String.class),
ClassName.get(RouteMeta.class));
ParameterSpec altas = ParameterSpec.builder(parameterizedTypeName, "atlas").build(); for (Map.Entry<String, List<RouteMeta>> entry : groupMap.entrySet()) {
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(Constant.METHOD_LOAD_INTO)
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.addParameter(altas); String groupName = entry.getKey();
List<RouteMeta> groupData = entry.getValue();
for (RouteMeta routeMeta : groupData) {
//函数体的添加
methodBuilder.addStatement("atlas.put(T.build(L,S,$S))",
routeMeta.getPath(),
ClassName.get(RouteMeta.class),
ClassName.get(RouteMeta.Type.class),
routeMeta.getType(),
ClassName.get(((TypeElement) routeMeta.getElement())),
routeMeta.getPath(),
routeMeta.getGroup());
}
String groupClassName = Constant.NAME_OF_GROUP + groupName;
TypeSpec typeSpec = TypeSpec.classBuilder(groupClassName)
.addSuperinterface(ClassName.get(iRouteGroup))
.addModifiers(Modifier.PUBLIC)
.addMethod(methodBuilder.build())
.build();
JavaFile javaFile = JavaFile.builder(Constant.PACKAGE_OF_GENERATE_FILE, typeSpec).build();
try {
javaFile.writeTo(filerUtils);
} catch (IOException e) {
e.printStackTrace();
}
rootMap.put(groupName, groupClassName); }
}/**
-
检查是否配置 group 如果没有配置 则从path截取出组名 * @param routeMeta
*/
private void categories(RouteMeta routeMeta) {
if (routeVerify(routeMeta)) {
log.i("Group : " + routeMeta.getGroup() + " path=" + routeMeta.getPath());
//分组与组中的路由信息
List<RouteMeta> routeMetas = groupMap.get(routeMeta.getGroup());
if (Utils.isEmpty(routeMetas)) {
routeMetas = new ArrayList<>();
routeMetas.add(routeMeta);
groupMap.put(routeMeta.getGroup(), routeMetas);
} else {
routeMetas.add(routeMeta);
}
} else {
log.i("Group info error:" + routeMeta.getPath());
}
}/**
-
验证path路由地址的合法性 * @param routeMeta
-
@return
*/
private boolean routeVerify(RouteMeta routeMeta) {
String path = routeMeta.getPath();
String group = routeMeta.getGroup();
// 必须以 / 开头来指定路由地址
if (!path.startsWith("/")) {
return false;
}
//如果group没有设置 我们从path中获得group
if (Utils.isEmpty(group)) {
String defaultGroup = path.substring(1, path.indexOf("/", 1));
//截取出的group还是空
if (Utils.isEmpty(defaultGroup)) {
return false;
}
routeMeta.setGroup(defaultGroup);
}
return true;
}
}
</pre>
第四步: 文件生成后,需要调用,通过反射,需要反射去创建实例!
先模拟调用的代码!
需要2个Map去装载组和类
public void test() {
EaseRouter_Root_app rootApp = new EaseRouter_Root_app();
HashMap<String, Class<? extends IRouteGroup>> rootMap = new HashMap<>();
rootApp.loadInto(rootMap);
//得到/main分组
Class<? extends IRouteGroup> aClass = rootMap.get("main");
try {
HashMap<String, RouteMeta> groupMap = new HashMap<>();
aClass.newInstance().loadInto(groupMap);
//得到MainActivity
RouteMeta main = groupMap.get("/main/main");
Class<?> mainActivityClass = main.getDestination();
Intent intent = new Intent(this, mainActivityClass);
startActivity(intent);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
具体:在application的时候去填充map
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">public class Warehouse {
// root 映射表 保存分组信息
static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>(); // group 映射表 保存组中的所有数据
static Map<String, RouteMeta> routes = new HashMap<>(); // group 映射表 保存组中的所有数据
static Map<Class, IService> services = new HashMap<>();
// TestServiceImpl.class , TestServiceImpl 没有再反射 /**
- 以键值对优先级的方式保存拦截器对象 / public static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>();
/* - 以集合的方式保存所有拦截器对象 */ public static List<IInterceptor> interceptors = new ArrayList<>(); }
</pre>
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">/**
-
分组表制作 */ private static void loadInfo() throws PackageManager.NameNotFoundException, InterruptedException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获得所有 apt生成的路由类的全类名 (路由表)
Set<String> routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
for (String className : routerMap) {
if (className.startsWith(ROUTE_ROOT_PAKCAGE + "." + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
//root中注册的是分组信息 将分组信息加入仓库中
((IRouteRoot) Class.forName(className).getConstructor().newInstance()).loadInto(Warehouse.groupsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + "." + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTOR)) {((IInterceptorGroup) Class.forName(className).getConstructor().newInstance()).loadInto(Warehouse.interceptorsIndex);
}
}
for (Map.Entry<String, Class<? extends IRouteGroup>> stringClassEntry : Warehouse.groupsIndex.entrySet()) {
Log.d(TAG, "Root映射表[ " + stringClassEntry.getKey() + " : " + stringClassEntry.getValue() + "]");
}
}</pre>
这里用到了CountDownLatch类,会分path一个文件一个文件的检索,等到所有的类文件都找到后便会返回这个Set<String>集合。
注意,Warehouse就是专门用来存放路由映射关系的类,里面保存着存路由信息的map,这在ARouter里面也是一样的。这段代码Warehouse.routes.get(card.getPath())通过path拿到对应的RouteMeta,这个RouteMeta里面保存了activityClass等信息。继续往下看,如果判断拿到的RouteMeta是空,说明这个路由地址还没有加载到map里面(初始化时为了节省性能,只会加载所有的分组信息,而每个分组下的路由映射关系,会使用懒加载,在首次用到的时候去加载)
下面就是用到了反射!!
<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">/**
- 准备卡片 * * @param card
*/ private void prepareCard(Postcard card) {
RouteMeta routeMeta = Warehouse.routes.get(card.getPath());
if (null == routeMeta) {
Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(card.getGroup());
if (null == groupMeta) {
throw new NoRouteFoundException("没找到对应路由:分组=" + card.getGroup() + " 路径=" + card.getPath());
}
IRouteGroup iGroupInstance;
try {
iGroupInstance = groupMeta.getConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("路由分组映射表记录失败.", e);
}
iGroupInstance.loadInto(Warehouse.routes);
//已经准备过了就可以移除了 (不会一直存在内存中)
Warehouse.groupsIndex.remove(card.getGroup());
//再次进入 else
prepareCard(card);
} else {
//类 要跳转的activity 或IService实现类
card.setDestination(routeMeta.getDestination());
card.setType(routeMeta.getType());
switch (routeMeta.getType()) {
case ISERVICE:
Class<?> destination = routeMeta.getDestination();
IService service = Warehouse.services.get(destination);
if (null == service) {
try {
service = (IService) destination.getConstructor().newInstance();
Warehouse.services.put(destination, service);
} catch (Exception e) {
e.printStackTrace();
}
}
card.setService(service);
break; default:
break;
}
}
}</pre>
最好的实现
网友评论