使用过阿里开源项目ARouter路由框架的都知道,为组件化开发打开了一扇大门。使用组件化的目的就是解决团队开发,各自负责各自的模块,互不干扰,模块之间能够完全解耦,加快开发效率。这样做还有一个好处就是,如果有一个功能模块不需要了,可以在app中删除该模块的依赖即可,不需要大量的删除代码。核心技术是Javapoet,没有了解它的可以看另外一篇文章javapoet简单实用
一、如何实现模块之间activity的跳转
试想一下,如果没有阿里的路由框架,我们如何实现模块之间的跳转,传统的intent.setClass(xxx)明显是不行的。那么有两种方式实现
1、反射
通过反射拿到要跳转的activity类。然后在通过intent.setClass(xxx)。代码如下:
Class<?> clazz = Class.forName("com.xinyartech.personal.Personal_MainActivity");
Intent intent = new Intent(this,clazz);
startActivity(intent);
这种方式你需要知道要操作类的完整路径,容易写错。
2、公共类管理
(1)先上管理类的代码:
public class JumpManager {
/**
* key 包名
* value 类集合
*/
public static Map<String, List<PathBean>> pathMap = new HashMap<>();
/**
* 添加到本地集合
* @param packageName 包名
* @param pathName 路径名
* @param clazz 类
*/
public static void joinGroup(String packageName, String pathName, Class<?> clazz) {
List<PathBean> pathBeans = pathMap.get(packageName);
if (pathBeans == null) {
pathBeans = new ArrayList<>();
pathBeans.add(new PathBean(pathName, clazz));
} else {
//是否已经保存class
for (PathBean pathBean : pathBeans) {
if (!pathName.equalsIgnoreCase(pathBean.getPathName())) {
pathBeans.add(new PathBean(pathName, clazz));
}
}
}
pathMap.put(packageName, pathBeans);
}
public static Class<?> getTargetClass(String packageName,String pathName){
List<PathBean> pathBeans = pathMap.get(packageName);
if(pathBeans != null){
for (PathBean pathBean : pathBeans) {
if(pathName.equalsIgnoreCase(pathBean.getPathName())){
return pathBean.getClazz();
}
}
}
return null;
}
/**
* 资源回收
*/
public static void recycleMap(){
pathMap.clear();
pathMap = null;
System.gc();
}
}
原理很简单,就是将所有模块的模块名和path路径及所有类以key-value的形式保存起来。需要跳转的时候需要根据模块名和path路径及类名找到class并返回。
(2)管理类需要在application中进行初始化
//添加到本地配置
JumpManager.joinGroup("app", "MainActivity", MainActivity.class);
JumpManager.joinGroup("main", "Main_MainActivity", Main_MainActivity.class);
JumpManager.joinGroup("personal", "Personal_MainActivity", Personal_MainActivity.class);
(3)在activity中如下跳转
Class<?> clazz = JumpManager.getTargetClass("main", "Main_MainActivity");
if (clazz != null) {
startActivity(new Intent(this, clazz));
}
这种方式不需要配置完整的包名路径,但是每增加一个类就需要在application中添加配置,并且类的名称不能写错。比较繁琐
3、javapoet
将复杂的工作交给javapoet去实现,开发者不需要它是如何实现的,只需要按照规范调用即可,像开源框架ARouter一样
二、路由实现模块之间activity的跳转
1、路由地址设计
所谓的路由地址就是标记当前Activity的,比如:path="/main/Main_MainActivity"。最终使用apt生成的文件格式如下:
public class ARouter$$Path$$personal implements ARouterLoadPath {
@Override
public Map<String, RouterBean> loadPath() {
Map<String,RouterBean> pathMap = new HashMap<>();
pathMap.put("/personal/Personal_Main2Activity",RouterBean.create(RouterBean.Type.ACTIVITY,Personal_Main2Activity.class,"/personal/Personal_Main2Activity","personal"));
pathMap.put("/personal/Personal_Main3Activity",RouterBean.create(RouterBean.Type.ACTIVITY,Personal_Main3Activity.class,"/personal/Personal_Main3Activity","personal"));
pathMap.put("/personal/Personal_MainActivity",RouterBean.create(RouterBean.Type.ACTIVITY,Personal_MainActivity.class,"/personal/Personal_MainActivity","personal"));
return pathMap;
}
}
最终返回map,key为路径名称,value为RouterBean对象。
2、路由组设计
所谓的路由组名称就是对应不同module名称(组名),存放当前组的路由地址,比如组名为group=“personal”。最终生成的文件格式如下:
public class ARouter$$Group$$personal implements ARouterLoadGroup {
@Override
public Map<String, Class<? extends ARouterLoadPath>> loadGroup() {
Map<String,Class<? extends ARouterLoadPath>> groupMap = new HashMap<>();
groupMap.put("personal",ARouter$$Path$$personal.class);
return groupMap;
}
}
最终返回map,key为组名,value为当前组的路由地址class。这里为什么要做路由组的设计?从代码上理解:通过路由组名group能够获取当前模块下的所有路由地址path集合,然后通过具体的路由地址能够获取相对应的class,从而完成跳转。如果没有路由组的设计,我们就需要从路由地址中加载全部的class,然后找到我们需要的class。假如应用中有3个模块,我们只用到了其中的一个模块,这样加载全部的class,会导致资源的浪费。
3、RouterBean设计
该对象主要定义了这几字段信息,如下:
- Type的枚举类型:默认是作用在Activity上,代码规范
- group:路由组名
- path:路由地址
- clazz:使用注解的类
- element:节点信息
4、javapoet文件生成
(1)遍历当前ARouter注解的类节点
(2)解析每一个节点类
第一步:为了检验当前注解是否在Activity的子类上,需要拿到Activity类的自描述
Constant.ACTIVITY = “android.app.Activity”;
第二步:遍历节点,拿到当前节点类的自描述,并把当前类注解信息封装成RouterBean对象。判断当前类是否继承至Activity,满足条件保存到本地临时map集合中
第三步:保存到本地临时map
map的key为组名,value为路由地址集合。注意保存之前会做传入路径的合法性判断,其中有一点是如果用户没有设置group,就会通过截取的方法获取group组名。
第四步:创建路由地址文件和路由组文件,比如ARouter&&Path&&personal,ARouter&&Group&&personal。
创建过程可仿照之前的测试类代码进程构建。
完成以上4步集成,编译生成apk,打开apk,在class.dex中找到包名底下的apt目录,查看生成文件,如下截图:
也可以在各个模块的build目录下查看生成的文件。