简单介绍
路由在组件化工程中有非常重要的作用,两个没有相互引用的module之间怎么通信呢。
可以使用EventBus,使用广播,使用类加载,使用反射,scheme,隐式意图等等,这些方法各自都有优缺点,现在开源用的比较多的路由框架中ARouter中使用的是类加载的方法下面我们也使用类加载的方式自己封装一个小路由。
那怎么使用类加载的方法来进行不同组件之间通信呢。很简单只要我们能拿到一个类的全类名就可以啦
比如,新建一个工程appcom.chs.mymodule.MainActivity,并创建两个module,一个订单组件com.chs.order.OrderActivity,一个积分组件com.chs.integral.IntegralActivity。现在从app模块跳到订单模块只需如下操作就可以啦
try {
Class<?> clzz = Class.forName("com.chs.order.OrderActivity");
Intent intent = new Intent(this,clzz);
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
如果每次都这么写类名的话有点麻烦,各种点容易写错。那可不可以封装一下,其实我们只要拿到OrderActivity中的类名就可以了。
所以我们可以把这些需要跳转的类保存起来,比如保存到一个map中,跳转的时候就通过key拿到类名,然后继续通过Intent跳转。
简单实现
首先新建一个实体类用来保存路径和对应的类
public class PathBean {
private String path;
private Class<?> clzz;
public PathBean() {
}
public PathBean(String path, Class<?> clzz) {
this.path = path;
this.clzz = clzz;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public Class<?> getClzz() {
return clzz;
}
public void setClzz(Class<?> clzz) {
this.clzz = clzz;
}
}
然后新建一个管理类,用来保存注册过来的路径,和类信息
public class RecordPathManager {
public static Map<String, List<PathBean>> groupMap = new HashMap<>();
public static void joinGroup(String groupName,String pathName,Class<?> clzz){
List<PathBean> pathBeans = groupMap.get(groupName);
if(pathBeans == null){
pathBeans = new ArrayList<>();
pathBeans.add(new PathBean(pathName,clzz));
groupMap.put(groupName,pathBeans);
}else {
if(!isExit(pathName,pathBeans)){
pathBeans.add(new PathBean(pathName,clzz));
}
groupMap.put(groupName,pathBeans);
}
}
private static boolean isExit(String pathName,List<PathBean> list){
for (PathBean bean : list) {
if(pathName.equals(bean.getPath())){
return true;
}
}
return false;
}
public static Class<?> getTargetClass(String groupName,String pathName){
List<PathBean> list = groupMap.get(groupName);
if(list == null){
return null;
}else {
for (PathBean bean : list) {
if(pathName.equalsIgnoreCase(bean.getPath())){
return bean.getClzz();
}
}
}
return null;
}
}
该类非常简单,一个Map,一个存的方法和一个取的方法。为了提高效率这里分一下组,每一个module是一个组,key就是这个module的名字,value就是该组下面的类信息的集合。
最后是怎么存呢,当然是存的越早越好,要不然还没存好就跳转显然拿不到相关的类。所以我们在app模块中的application中存
应用打包的时候,app模块肯定是依赖的所有的模块,所以子模块中的类它肯定也能拿到。所以注册的代码如下
public class App extends BaseApplication {
@Override
public void onCreate() {
super.onCreate();
RecordPathManager.joinGroup("order","OrderActivity", OrderActivity.class);
RecordPathManager.joinGroup("integral","IntegralActivity", IntegralActivity.class);
......
}
}
将需要跳转的类activity的模块名,类名和类信息保存到管理类的Map中。使用的时候如下
try {
Class<?> clzz = RecordPathManager.getTargetClass("integral","IntegralActivity");
Intent intent = new Intent(this,clzz);
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
看起来比开始简单了一点点,不过这个在activity中一个一个的注册也是太麻烦,就几个类还好,几十上百的类估计会把自己写吐了,那能不能让系统帮我们写注册的代码呢,当然可以啦,这时候就用到APT的技术来实现啦。
使用APT自动完成注册。
下面仿照ARouter来实现一个简单跳转的路由,
项目结构如上图:
- annotation是注解module 是个java module
- compiler是注解处理器 必须是个java module
- order和integral是两个字module
- arouter用来定义存储的规范
先在annotation中定义一个编译时注解
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface ARouter {
String path();
String group() default "";
}
在定义一个RouterBean,相当于前面简单实现中的PathBean对象,用来存储路径,类,组名等。
public class RouterBean {
public enum Type{
/**
* activity类型
*/
ACTIVITY;
}
private Type mType;
/**
* 类结点
*/
private Element mElement;
/**
* 组名
*/
private String group;
/**
* 路由的地址
*/
private String path;
private Class<?> mClazz;
private RouterBean() {
}
private RouterBean(Type type, Class<?> clazz, String path, String group) {
this.mType = type;
this.mClazz = clazz;
this.path = path;
this.group = group;
}
public static RouterBean create(Type type,Class<?> clazz,String path,String group){
return new RouterBean(type,clazz,path,group);
}
private RouterBean(Builder builder) {
mElement = builder.mElement;
group = builder.group;
path = builder.path;
}
public Type getType() {
return mType;
}
public Element getElement() {
return mElement;
}
public String getGroup() {
return group;
}
public String getPath() {
return path;
}
public Class<?> getClzz() {
return mClazz;
}
public void setType(Type type) {
mType = type;
}
public void setGroup(String group) {
this.group = group;
}
public void setPath(String path) {
this.path = path;
}
public static final class Builder{
private Element mElement;
private String group;
private String path;
public Builder setElement(Element element) {
mElement = element;
return this;
}
public Builder setGroup(String group) {
this.group = group;
return th