arouter实现activity跳转原理

arouter实现activity跳转原理一、思路分析arouter让我们可以非常简单地实现组件间页面跳转,实现的基本思路是1.在对应的activity上加上注解,通过apt技术来自动生成代码,代码能将activity对应路径和class添加到路由表中;2.通过扫描获取所有类,遍历自动执行步骤1中所生成地代码,从而路由表中有了对应地数据,路由表的数据结构为Map<String,Class<?e…

大家好,又见面了,我是你们的朋友全栈君。

一、思路分析

arouter让我们可以非常简单地实现组件间页面跳转,实现的基本思路是   

1. 在对应的activity上加上注解,通过apt技术来自动生成代码,代码能将 activity对应路径 和 class 添加到路由表中;

2. 通过扫描获取所有类,遍历自动执行步骤1中所生成地代码,从而路由表中有了对应地数据,路由表的数据结构为 Map<String,Class<? extends Activity>> routes;

3. 进行跳转时,通过路径可在路由表中找到对应的acitivity,从而实现跳转

二、源码分析

1. 注解

注解编译中,利用自定义注解 @Route 设置路径,在RouteProcessor的process方法中生成代码,代码中可将对应的路径、目标activity添加到路由表

//Route.java 自定义注解Route
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface Route {
    String path();
    String group() default "";
    String name() default "";
   int extras() default Integer.MIN_VALUE;
   int priority() default -1;
}

//RouteProcessor.java 注解处理器
public class RouteProcessor extends AbstractProcessor {
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        if (CollectionUtils.isNotEmpty(annotations)) {
            //获取 Route注解的所有节点
            Set<? extends Element> routeElements = roundEnv.getElementsAnnotatedWith(Route.class);
            try {
                logger.info(">>> Found routes, start... <<<");
                //处理节点
                this.parseRoutes(routeElements);

            } catch (Exception e) {
                logger.error(e);
            }
            return true;
        }

        return false;
    }

    private void parseRoutes(Set<? extends Element> routeElements) throws IOException {
        ...
                    //生成路由表内容
                    loadIntoMethodOfGroupBuilder.addStatement(
                            "atlas.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, " + (StringUtils.isEmpty(mapBody) ? null : ("new java.util.HashMap<String, Integer>(){
  
  {" + mapBodyBuilder.toString() + "}}")) + ", " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
                            routeMeta.getPath(),
                            routeMetaCn,
                            routeTypeCn,
                            className,
                            routeMeta.getPath().toLowerCase(),
                            routeMeta.getGroup().toLowerCase());

                    routeDoc.setClassName(className.toString());
                    routeDocList.add(routeDoc);
                }

                // Generate groups
                String groupFileName = NAME_OF_GROUP + groupName;
                JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
                        TypeSpec.classBuilder(groupFileName)
                                .addJavadoc(WARNING_TIPS)
                                .addSuperinterface(ClassName.get(type_IRouteGroup))
                                .addModifiers(PUBLIC)
                                .addMethod(loadIntoMethodOfGroupBuilder.build())
                                .build()
                ).build().writeTo(mFiler);

                logger.info(">>> Generated group: " + groupName + "<<<");
                rootMap.put(groupName, groupFileName);
                docSource.put(groupName, routeDocList);
            }

          ...

            // 将含有路由表内容的java文件存到磁盘中
            String rootFileName = NAME_OF_ROOT + SEPARATOR + moduleName;
            JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
                    TypeSpec.classBuilder(rootFileName)
                            .addJavadoc(WARNING_TIPS)
                            .addSuperinterface(ClassName.get(elements.getTypeElement(ITROUTE_ROOT)))
                            .addModifiers(PUBLIC)
                            .addMethod(loadIntoMethodOfRootBuilder.build())
                            .build()
            ).build().writeTo(mFiler);

        }
    }
}

上述实现了在编译期生成路由表,生成的路由表在app/build/intermediates/classes/包名/routes下,自动生成的代码如下所示:

 

public class ARouter$$Group$$test implements IRouteGroup {
    atlas.put("/test/activity2", RouteMeta.build(RouteType.ACTIVITY, Test2Activity.class, "/test/activity2", "test", new HashMap<String, Integer>() {
            {
                this.put("key1", 8);
            }
        }, -1, -2147483648));
        atlas.put("/test/activity3", RouteMeta.build(RouteType.ACTIVITY, Test3Activity.class, "/test/activity3", "test", new HashMap<String, Integer>() {
            {
                this.put("name", 8);
                this.put("boy", 0);
                this.put("age", 3);
            }
        }, -1, -2147483648));
}

2. 扫描获取所有类

步骤1中生成的代码并不会自动执行,所以需要通过扫描获取所有class,遍历执行添加到路由表的方法

//LogisticsCenter.java
public synchronized static void init(Context context, ThreadPoolExecutor tpe){
    //通过扫描获取到所有满足要求的class
    routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
    for (String className : routerMap) {
        //执行添加到路由表的方法
        ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
    }
}

3. 跳转

有了路由表,跳转时,通过传入目标activity路径,arouter会根据路径从路由表中找到目标activity,然后将目标activity设置到intent上,再通过startActivity来实现跳转。 

//_ARouter.java
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
        final Context currentContext = null == context ? mContext : context;

        switch (postcard.getType()) {
            case ACTIVITY:
                // 构建intent,设置目标activity,postcard.getDestination()即 XxxActivity.class
                final Intent intent = new Intent(currentContext, postcard.getDestination());
                intent.putExtras(postcard.getExtras());

                // 设置flag
                int flags = postcard.getFlags();
                if (-1 != flags) {
                    intent.setFlags(flags);
                } else if (!(currentContext instanceof Activity)) {    // Non activity, need less one flag.
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                }

                // Set Actions
                String action = postcard.getAction();
                if (!TextUtils.isEmpty(action)) {
                    intent.setAction(action);
                }

                // 在主线程中执行跳转操作
                runInMainThread(new Runnable() {
                    @Override
                    public void run() {
                        //通过startActivity来实现跳转
                        startActivity(requestCode, currentContext, intent, postcard, callback);
                    }
                });

                break;
            ...
        }

        return null;
    }

    Postcard类中包含了利用@Route注解配置的路径、携带参数、action、目标activity(即destination)等,把postcard中的参数设置到intent上,然后通过startActivity来进行跳转。

如需了解更多请点击

java注解编译学习

arouter原理官方文档

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/143535.html原文链接:https://javaforall.net

(0)
上一篇 2022年5月21日 下午1:20
下一篇 2022年5月21日 下午1:20


相关推荐

  • Spring-boot_Spring Boot

    Spring-boot_Spring Boot1概述Jasypt是一个加密库,Github上有一个集成了Jasypt的SpringBoot库,叫jasypt-spring-boot,本文演示了如何使用该库对配置文件进行加密。2依赖首先添加依赖:<dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId>

    2026年4月14日
    5
  • 浏览器下载文件名乱码_ie浏览器下载文件名字是乱码

    浏览器下载文件名乱码_ie浏览器下载文件名字是乱码FireFox下载时文件名乱码问题解决

    2022年4月20日
    54
  • Grok-Mirror:一键部署可盈利的Grok镜像站

    Grok-Mirror:一键部署可盈利的Grok镜像站

    2026年3月15日
    3
  • AI重新定义web及谷歌验证码安全

    AI重新定义web及谷歌验证码安全云给安全带来的影响距离2006年Amazon发布EC2服务已经过去了11年,在这11年里,发生的不仅仅是AWS收入从几十万美金上涨到100多亿美金,更重要的是云计算已经走进每一家企业。根据信通院发布的“2016云计算白皮书”,目前近90%的企业都已经开始使用云计算(包括公有云、私有云等),这说明大规模云化对于企业而言已经不只是趋势,更是确凿的既成事实。云化普及的同时也给安全带来很多挑战,主要包括:云化导致以硬件设备为主的传统安全方式失效。我在跟企业交流时,不止一家企业提出了这样的担心:在上公有云的过程

    2022年5月27日
    41
  • plot中的 markersize

    plot中的 markersizemarkersize plot 0 1 2 3 4 0 2 5 6 9 c pentagram markersize 15 画图的命令是 marker 是图上画上点的地方表上符号 不如点 方框 圆框 十字 星号 等等后面的 size 就是其大小了 不知道值的话 可以画完图点编辑框上面的箭头 然后双击画的图 下面出现属性框 marker 项后面的数字下拉菜单就是 size 选择合适的

    2026年3月17日
    2
  • [时间序列分析][4]–AR模型,MA模型,ARMA模型介绍[通俗易懂]

    [时间序列分析][4]–AR模型,MA模型,ARMA模型介绍[通俗易懂]自相关和偏自相关的两个函数代码由于后面会经常画一组序列自相关和偏自相关的图像,所以就把自己写的这个两个画图的函数的代码贴上,供大家参考。首先是自相关的函数输入的三个参数分别是{数据,滞后数,置信度

    2022年8月2日
    10

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号