Andorid组件化跳转路由

简单介绍

路由在组件化工程中有非常重要的作用,两个没有相互引用的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> groupMap = new HashMap<>();

    public static void joinGroup(String groupName,String pathName,Class clzz){
        List 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 list){
        for (PathBean bean : list) {
            if(pathName.equals(bean.getPath())){
                return true;
            }
        }
        return false;
    }

    public static Class getTargetClass(String groupName,String pathName){
        List 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 this;
        }

        public Builder setPath(String path) {
            this.path = path;
            return this;
        }
        public RouterBean build(){
            if(path==null||path.length()==0){
              throw new IllegalArgumentException("path 为空 比如 /app/MainActivity");
            }
            return new RouterBean(this);
        }
    }

    @Override
    public String toString() {
        return "RouterBean{" +
                "group='" + group + '\'' +
                ", path='" + path + '\'' +
                '}';
    }
}

下面在arouter_api 这个module中定义两个接口ARouterLoadGroup和ARouterLoadPath。
一个工程中会有很多个module,如果每次把说有的类都加载比较耗费内存,所以设计一个组来管理,组名就是当前的module的名字,它下面管理着该module下的所有注册的activity类,只有用户到了该module的时候才会加载
我们生成类会继承自这两个接口。

/**
 *key:"app", value:"app"分组对应的路由详细对象类
 */
public interface ARouterLoadGroup {
    
    Map> loadGroup();

}
public interface ARouterLoadPath {
    /**
     * 比如传入 /app/MainActivity  通过app找到对应的组,然后通过/app/MainActivity找到对应的class
     */
    Map loadPath();
}

下面来到了重头戏注解管理器compiler中。
先在其gradle文件中引入相关的工具

apply plugin: 'java-library'

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    compileOnly'com.google.auto.service:auto-service:1.0-rc4'
    annotationProcessor'com.google.auto.service:auto-service:1.0-rc4'

    // 帮助我们通过类调用的形式来生成Java代码
    implementation "com.squareup:javapoet:1.9.0"

    // 依赖注解
    implementation project(':annotation')
}

// java控制台输出中文乱码
tasks.withType(JavaCompile) {
    options.encoding = "UTF-8"
}

sourceCompatibility = "7"
targetCompatibility = "7"

auto-service是谷歌提供的可以用来自动触发注解管理器运行。
javapoet是著名的square公司出品,用来生成java类的工具
javapoet有8个常用的类
Andorid组件化跳转路由_第1张图片
JavaPort字符串的格式化规则
Andorid组件化跳转路由_第2张图片

上面两个表中的数据比较重要,下面写注解管理器的时候都会用到。

具体用法可以到https://github.com/square/javapoet中查看
因为相关的类是我们自己生成的,所以事先我们肯定知道它最后的样子,先看看需要生成的类的最后的样子

public class ARouter$$Group$$app implements ARouterLoadGroup {
  @Override
  public Map> loadGroup() {
    Map> groupMap = new HashMap<>();
    groupMap.put("app",ARouter$$Path$$app.class);
    return groupMap;
  }
}
public class ARouter$$Path$$app implements ARouterLoadPath {
  @Override
  public Map loadPath() {
    Map pathMap = new HashMap<>();
    pathMap.put("/app/Main2Activity",RouterBean.create(RouterBean.Type.ACTIVITY,Main2Activity.class,"/app/Main2Activity","app"));
    pathMap.put("/app/MainActivity",RouterBean.create(RouterBean.Type.ACTIVITY,MainActivity.class,"/app/MainActivity","app"));
    return pathMap;
  }
}

分别继承前面定义的两个接口,一个用来初始化该组的map,并存入路径信息,一个是路径信息类,初始化并保存相关的路径和类信息。

需要注意的是第一个类中使用了第二个类,所以生成类的时候要先生成第二个类,然后在生成第一个类
下面比对着上面的两个类开始编写注解管理器:

@AutoService(Processor.class)
//这里是注解的全类名比如 com.chs.annotation.ARouter,这里保存到一个常量中了
@SupportedAnnotationTypes(Const.ACTIVITY_ANNOTATION_TYPE)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedOptions({Const.MODULE_NAME,Const.APT_PACKAGE})
public class ARouterProcessor extends AbstractProcessor {
    /**
     * 结点工具类  类 函数 属性都是element
     */
    private Elements elementUtils;
    /**
     * 类信息工具
     */
    private Types typeUtils;
    /**
     * 打印工具类
     */
    private Messager mMessager;
    /**
     * 文件生成器
     */
    private Filer mFiler;
    /**
     * 组名
     */
    private String moduleName;
    /**
     * 生成的apt文件的路径 包名
     */
    private String packageNameForAPT;

    /**
     * 临时存放路径的类 生成的时候遍历
     * key 组名 如app value 组的路由路径 如 ARouter$$Path$$app.class
     */
    private Map> tempPathMap = new HashMap<>();
    /**
     * 临时存放组的类
     * 比如 key app  value ARouter$$Path$$app
     */
    private Map tempGroupMap = new HashMap<>();


    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        elementUtils = processingEnv.getElementUtils();
        typeUtils = processingEnv.getTypeUtils();
        mMessager = processingEnv.getMessager();
        mFiler = processingEnv.getFiler();

        Map options = processingEnv.getOptions();
        mMessager.printMessage(Diagnostic.Kind.NOTE,options.toString());
        if(!EmptyUtils.isEmpty(options)){
            moduleName = options.get(Const.MODULE_NAME);
            packageNameForAPT = options.get(Const.APT_PACKAGE);
            mMessager.printMessage(Diagnostic.Kind.NOTE,"moduleName:"+moduleName);
            mMessager.printMessage(Diagnostic.Kind.NOTE,"packageNameForAPT:"+packageNameForAPT);
        }
        if(EmptyUtils.isEmpty(moduleName)||EmptyUtils.isEmpty(packageNameForAPT)){
            throw new IllegalArgumentException("注解处理器需要的参数 module或packageName为空,需要在gradle中配置");
        }

    }

    @Override
    public boolean process(Set set, RoundEnvironment roundEnvironment) {
        if(!EmptyUtils.isEmpty(set)){
           //获取所有被ARouter注解的元素集合
            Set elements = roundEnvironment.getElementsAnnotatedWith(ARouter.class);
            if(!EmptyUtils.isEmpty(elements)){
                try {
                    parseElements(elements);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return true;
        }
        return false;
    }

    /**
     * 解析所有别ARouter注解的元素集合
     * @param elements
     */
    private void parseElements(Set elements) throws IOException {
        //通过element工具获取Activity的类型 activity的路径为 android.app.Activity
        TypeElement typeElement = elementUtils.getTypeElement(Const.ACTIVITY);
        //获取activity的TypeMirror
        TypeMirror activityTypeMirror = typeElement.asType();
        for (Element element : elements) {
            //获取每个元素的类信息
            TypeMirror elementTypeMirror = element.asType();
            mMessager.printMessage(Diagnostic.Kind.NOTE,"遍历的元素信息为:"+elementTypeMirror.toString());

            //获取每个类上的ARouter 注解对应的path值
            ARouter aRouter = element.getAnnotation(ARouter.class);
            //封装RouterBean
            RouterBean routerBean = new RouterBean.Builder()
                    .setGroup(aRouter.group())
                    .setPath(aRouter.path())
                    .setElement(element)
                    .build();
            //防止用户乱写 判断注解是作用在activity上面
            if(typeUtils.isSubtype(elementTypeMirror,activityTypeMirror)){
                  routerBean.setType(RouterBean.Type.ACTIVITY);
            }else {
                throw new IllegalArgumentException("@ARouter 目前只能用在Activity上面");
            }

            //存放到临时的map中 方便后面组装
            valueOfPathMap(routerBean);
        }
        //ARouterLoadGroup和ARouterLoadPath的类型
        TypeElement groupElementType = elementUtils.getTypeElement(Const.AROUTER_GROUP);
        TypeElement pathElementType = elementUtils.getTypeElement(Const.AROUTER_PATH);
        //1 先生成路由的path文件 比如 ARouter$$Path$$order
        createPathFile(pathElementType);
        //2 在生成路由的组文件 比如 ARouter$$GROUP$$order 因为组中用到了上面的类
        createGroupFile(groupElementType,pathElementType);
    }

    /**
     * 生成group对应的path ARouter$$Path$$order
     * @param pathElementType
     */
    private void createPathFile(TypeElement pathElementType) throws IOException {
       if(EmptyUtils.isEmpty(tempPathMap)){
           return;
       }
       //方法的返回值Map
        TypeName typeName = ParameterizedTypeName.get(
                ClassName.get(Map.class),ClassName.get(String.class),ClassName.get(RouterBean.class));
       //遍历分组,每一个分组创建一个路径文件ARouter$$Path$$order
        for (Map.Entry> entry : tempPathMap.entrySet()) {
           //方法体 public Map loadPath() {}
            MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(Const.PATH_METHOD_NAME)
                    .addAnnotation(Override.class)
                    .addModifiers(Modifier.PUBLIC)
                    .returns(typeName);
            //Map pathMap = new HashMap<>();
            methodBuilder.addStatement("$T<$T,$T> $N = new $T<>()",ClassName.get(Map.class)
            ,ClassName.get(String.class),ClassName.get(RouterBean.class),Const.PATH_PARAMA_NAME
            ,HashMap.class);
            List values = entry.getValue();
            for (RouterBean bean : values) {
                // pathMap.put("/order/Order_MainActivity",RouterBean.create(RouterBean.Type.ACTIVITY
                //        , Order_MainActivity.class,"/order/Order_MainActivity","order"));
                methodBuilder.addStatement("$N.put($S,$T.create($T.$L,$T.class,$S,$S))",
                        Const.PATH_PARAMA_NAME,
                        bean.getPath(),
                        ClassName.get(RouterBean.class),
                        ClassName.get(RouterBean.Type.class),
                        bean.getType(),
                        ClassName.get((TypeElement) bean.getElement()),
                        bean.getPath(),
                        bean.getGroup());
            }
            methodBuilder.addStatement("return $N",Const.PATH_PARAMA_NAME);

            String finalClassName = Const.PATH_FILD_NAME + entry.getKey();
            mMessager.printMessage(Diagnostic.Kind.NOTE,
                    "APT生成的path类为"+packageNameForAPT+finalClassName);
            JavaFile.builder(packageNameForAPT,
                    TypeSpec.classBuilder(finalClassName)
                            //该类实现的接口
                            .addSuperinterface(ClassName.get(pathElementType))
                            .addModifiers(Modifier.PUBLIC)
                            //方法体
                            .addMethod(methodBuilder.build())
                            .build())
                     .build()
            .writeTo(mFiler);

            tempGroupMap.put(entry.getKey(),finalClassName);
        }
    }

    /**
     * 生成group  ARouter$$Group$$order
     * @param groupElementType
     * @param pathElementType
     */
    private void createGroupFile(TypeElement groupElementType, TypeElement pathElementType) throws IOException {
        if(EmptyUtils.isEmpty(tempPathMap)||EmptyUtils.isEmpty(tempGroupMap)){
                return;
        }
        //public Map> loadGroup() {
        TypeName methodReturn = ParameterizedTypeName.get(ClassName.get(Map.class),ClassName.get(String.class)
        ,ParameterizedTypeName.get(ClassName.get(Class.class),
                        //Class
                        WildcardTypeName.subtypeOf(ClassName.get(pathElementType))));
        //方法体 public Map loadPath() {}
        MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(Const.GROUP_METHOD_NAME)
                .addAnnotation(Override.class)
                .addModifiers(Modifier.PUBLIC)
                .returns(methodReturn);
        //  Map> groupMap = new HashMap<>();
        methodBuilder.addStatement("$T<$T,$T> $N = new $T<>()",
                ClassName.get(Map.class)
                ,ClassName.get(String.class),
                ParameterizedTypeName.get(ClassName.get(Class.class),
                        WildcardTypeName.subtypeOf(ClassName.get(pathElementType))),
                Const.GROUP_PARAMA_NAME
                ,HashMap.class);
        //groupMap.put("order",ARouter$$Path$$order.class);
        for (Map.Entry entry : tempGroupMap.entrySet()) {
            methodBuilder.addStatement("$N.put($S,$T.class)",
                    Const.GROUP_PARAMA_NAME,
                    entry.getKey(),
                    //指定的包名下
                    ClassName.get(packageNameForAPT,entry.getValue()));
        }
        methodBuilder.addStatement("return $N",Const.GROUP_PARAMA_NAME);
        String finalClassName = Const.GROUP_FILD_NAME + moduleName;
        mMessager.printMessage(Diagnostic.Kind.NOTE,
                "APT生成的group类为"+packageNameForAPT+finalClassName);
        JavaFile.builder(packageNameForAPT,
                TypeSpec.classBuilder(finalClassName)
                        //该类实现的接口
                        .addSuperinterface(ClassName.get(groupElementType))
                        .addModifiers(Modifier.PUBLIC)
                        //方法体
                        .addMethod(methodBuilder.build())
                        .build())
                .build()
                .writeTo(mFiler);
    }

    private static boolean isExit(String pathName,List list){
        for (RouterBean bean : list) {
            if(pathName.equalsIgnoreCase(bean.getPath())){
                return true;
            }
        }
        return false;
    }
    private void valueOfPathMap(RouterBean routerBean) {
        if(checkRouterPath(routerBean)){
            mMessager.printMessage(Diagnostic.Kind.NOTE,"routerBean对象"+routerBean.toString());
            //开始放入map
            List list = tempPathMap.get(routerBean.getGroup());
            if(EmptyUtils.isEmpty(list)){
                list = new ArrayList<>();
                list.add(routerBean);
                tempPathMap.put(routerBean.getGroup(),list);
            }else {
                if(!isExit(routerBean.getPath(),list)){
                    list.add(routerBean);
                }
            }
        }else {
            mMessager.printMessage(Diagnostic.Kind.ERROR,"@ARouter注解没有按照规范些 /app/MainActivity");
        }

    }

    private boolean checkRouterPath(RouterBean routerBean) {
        String path = routerBean.getPath();
        String group = routerBean.getGroup();
        if(EmptyUtils.isEmpty(path)||!path.startsWith("/")){
            mMessager.printMessage(Diagnostic.Kind.ERROR,"@ARouter注解没有按照规范些 /app/MainActivity");
            return false;
        }
        if(path.lastIndexOf("/")== 0){
            mMessager.printMessage(Diagnostic.Kind.ERROR,"@ARouter注解没有按照规范些 /app/MainActivity");
            return false;
        }
        String finalGroup = path.substring(1,path.indexOf("/",1));
        mMessager.printMessage(Diagnostic.Kind.NOTE,"finalGroup:"+finalGroup);

        if(finalGroup.contains("/")){
            mMessager.printMessage(Diagnostic.Kind.ERROR,"@ARouter注解没有按照规范些 /app/MainActivity");
            return false;
        }
        if(!EmptyUtils.isEmpty(group)&&!group.equalsIgnoreCase(moduleName)){
            mMessager.printMessage(Diagnostic.Kind.ERROR,"group必须是当前模块的名字");
            return false;
        }else {
            routerBean.setGroup(finalGroup);
        }
        return true;
    }
}
public class EmptyUtils {
    public static boolean isEmpty(CharSequence c){
       return c==null||c.length()==0;
    }
    public static boolean isEmpty(Collection c){
       return c==null||c.isEmpty();
    }
    public static boolean isEmpty(final Map c){
       return c==null||c.isEmpty();
    }
}
//Const类中都是一些常量字符串。

上面类上的@SupportedOptions 这个注解可以接收从build.grale中传过来的参数。比如我们在build.gradle中把module的名字和最后生成的类的包名传过来

//rootProject.ext.packageNameForAPT是在gradle中定义的常量com.chs.module.apt
  javaCompileOptions {
            annotationProcessorOptions {
                arguments = [moduleName: project.getName(), packageNameForAPT: rootProject.ext.packageNameForAPT]
            }
        }

在每个需要生成类的module中都引入注解和注解管理器

 implementation project(':annotation')
 annotationProcessor project(':complier')

最后重新build工程,在对应module的build文件夹下就会生成相应的类了,比如appmodule中在路径 \app\build\generated\source\apt\debug\com.chs.module.apt下面就可以看到生成的类ARouter G r o u p Group Groupapp和ARouter P a t h Path Pathapp

最后使用生成的类来实现跳转

 ARouterLoadGroup group = new ARouter$$Group$$order();
        Map> map = group.loadGroup();
        // 通过order组名获取对应路由路径对象
        Class clazz = map.get("order");

        try {
            // 类加载动态加载路由路径对象
            ARouter$$Path$$order path = (ARouter$$Path$$order) clazz.newInstance();
            Map pathMap = path.loadPath();
            // 获取目标对象封装
            RouterBean bean = pathMap.get("/order/Order_MainActivity");

            if (bean != null) {
                Intent intent = new Intent(this, bean.getClzz());
                intent.putExtra("name", "lily");
                startActivity(intent);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

最后集成打包的时候 所有子模块app、order、integral通过APT生成的类文件都会打包到apk里面,不用担心找不到
运行之后会看到跳转成功,不过跳转一次写这么多代码好像不是我们想要的啊,我们理想中的跳转应该是下面的样子

  RouterManager.getInstance().build("/personal/Personal_MainActivity")
                .withString("name","chs")
                .navigation(this);

这就需要我们把前面的跳转的代码封装一下啦

public class RouterManager {

    private static  RouterManager instence;
    private LruCache groupCache;
    private LruCache  pathCache;
    private String path;
    private String group;
    private static final String GROUP_PRFIX_NAME = ".ARouter$$Group$$";

    public static RouterManager getInstance(){
        if(instence == null){
            synchronized (RouterManager.class){
                if(instence == null){
                    instence = new RouterManager();
                }
            }
        }
        return instence;
    }

    public RouterManager() {
        groupCache = new LruCache<>(100);
        pathCache = new LruCache<>(100);
    }

    public BundleManager build(String path) {
        if (TextUtils.isEmpty(path) || !path.startsWith("/")) {
            throw new IllegalArgumentException("未按规范配置,如:/app/MainActivity");
        }
        group = subFromPath2Group(path);
        this.path = path;
        return new BundleManager();
    }

    /**
     * 判断path 的格式是否符合规范
     * @param path 需要当行的路径
     * @return
     */
    private String subFromPath2Group(String path) {
        if(path.lastIndexOf("/") == 0){
            throw new IllegalArgumentException("@ARouter注解未按规范配置,如:/app/MainActivity");
        }
        String finalGroup = path.substring(1, path.indexOf("/", 1));
        if (TextUtils.isEmpty(finalGroup)) {
            throw new IllegalArgumentException("@ARouter注解未按规范配置,如:/app/MainActivity");
        }
        return finalGroup;
    }

    public Object navigation(Context context, BundleManager bundleManager, int code) {
        String groupClassName = context.getPackageName() + ".apt" + GROUP_PRFIX_NAME + group;
        Log.e("chs >>> ", "groupClassName -> " + groupClassName);

        try {
        ARouterLoadGroup aRouterLoadGroup = groupCache.get(groupClassName);
            if(aRouterLoadGroup == null){
                Class clazz  = Class.forName(groupClassName);
                aRouterLoadGroup = (ARouterLoadGroup) clazz.newInstance();
                groupCache.put(groupClassName,aRouterLoadGroup);
            }
            // 获取路由路径类ARouter$$Path$$app 的map
            if (aRouterLoadGroup.loadGroup().isEmpty()) {
                throw new RuntimeException("路由加载失败");
            }

            ARouterLoadPath aRouterLoadPath = pathCache.get(path);
            if(aRouterLoadPath == null){
                Class clazz = aRouterLoadGroup.loadGroup().get(group);
                if (clazz != null){
                    aRouterLoadPath = (ARouterLoadPath) clazz.newInstance();
                    pathCache.put(path,aRouterLoadPath);
                }
            }

            if(aRouterLoadPath.loadPath().isEmpty()){
                throw new RuntimeException("路由路径加载失败");
            }
            RouterBean routerBean = aRouterLoadPath.loadPath().get(path);
            if (routerBean != null) {
                switch (routerBean.getType()){
                    case ACTIVITY:
                        Intent intent = new Intent(context, routerBean.getClzz());
                        intent.putExtras(bundleManager.getBundle());

                        if (bundleManager.isResult()) {
                            ((Activity) context).setResult(code, intent);
                            ((Activity) context).finish();
                        }else {
                            if (code > 0) { // 跳转时是否回调
                                ((Activity) context).startActivityForResult(intent, code, bundleManager.getBundle());
                            } else {
                                context.startActivity(intent, bundleManager.getBundle());
                            }
                        }
                        break;
                }
            }

        }catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}

上面代码中的核心类其实就是前面的跳转的代码

通过传入的path路径,截取出group的名字
然后根据组的名字,包名,和定义好的前缀拼接出完成的组类的名字,然后通过类加载实例化出这个对象
实例完成之后调用其loadGroup方法,根据group找出存path的map,最后拿到相关的class执行跳转。
为了提高运行的效率,使用两个LruCache类来缓存组类和path类,先去这里面取,取不到在创建。

我们在activity中跳转的时候,有时候会传递参数,所以前面的代码中创建了一个类BundleManager来管理参数,将参数封装到Bundle中传递,BundleManager类很简单就是封装了一下Bundle。

public class BundleManager {

    private Bundle bundle = new Bundle();
    private boolean isResult;

    public Bundle getBundle() {
        return bundle;
    }

    public boolean isResult() {
        return isResult;
    }

    public BundleManager withString(@NonNull String key, @Nullable String value) {
        bundle.putString(key, value);
        return this;
    }

    public BundleManager withResultString(@NonNull String key, @Nullable String value) {
        bundle.putString(key, value);
        isResult = true;
        return this;
    }
    public BundleManager withBoolean(@NonNull String key, boolean value) {
        bundle.putBoolean(key, value);
        return this;
    }
    public BundleManager withInt(@NonNull String key, int value) {
        bundle.putInt(key, value);
        return this;
    }

    public BundleManager withBundle(@NonNull Bundle bundle) {
        this.bundle = bundle;
        return this;
    }

    public Object navigation(Context context) {
       return RouterManager.getInstance().navigation(context,this,-1);
    }
    public Object navigation(Context context,int code) {
       return RouterManager.getInstance().navigation(context,this,code);
    }
}

OK到这里一个简单的跳转路由就完成啦。

你可能感兴趣的:(安卓日常)