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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • ASP.NET 如何使用 SqlTransaction

    ASP.NET 如何使用 SqlTransactiontransaction属性: 1.原子性:事务是一个完整的操作,事务的各元素师不可分的。2.一致性:事务开始时和完成时,数据必须处于一致的状态。3.隔离性:对数据进行修改的所有并发事务是彼此隔离的。4.持久性:事务完成后,它对系统的影响是永久的。  ASP.NET使用SqlTransaction处理事务操作 SqlTransaction类是对SQLSe

    2022年5月1日
    35
  • Vs2010_labview读取CPU序列号

    Vs2010_labview读取CPU序列号   用VS2008有些日子,刚刚才发现AboutMVS是有天数限制的(90),郁闷,只好在网上找序列号,不错,把刚刚找到的VS2008可升级序列号发给大家。          1.VisualStudio2008ProfessionalEdition:     XMQ2Y-4T3V6-XJ48Y-D3K2V-6C4WT      2.VisualStudio2008

    2022年8月10日
    7
  • 蓝牙开发心得体会

    蓝牙开发心得体会一、关于布局适配建议1、不要使用绝对布局2、尽量使用match_parent而不是fill_parent。3、能够使用权重的地方尽量使用权重(android:layout_weight)4、如果是纯色背景,尽量使用android的shape自定义。5、如果需要在特定分辨率下适配,可以在res目录上新建layout-HxW.xml的文件夹。比如要适配10

    2022年6月20日
    28
  • Navicat15 注册激活码【最新永久激活】「建议收藏」

    (Navicat15 注册激活码)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html…

    2022年3月27日
    2.0K
  • 找不到vcruntime140.dll 无法执行代码_Win11一键修复所有dll缺失

    找不到vcruntime140.dll 无法执行代码_Win11一键修复所有dll缺失welcometomyblog问题描述:安装mysql时报错:由于找不到vcruntime140_1.dll,无法继续执行代码解决方法:这是缺少了动态链接库(.ddl文件),跟mysql无关,下载一份即可,下载地址,拖到下面,我下载的是64位版本的压缩包解压后将vcruntime140_1.dll复制到C:\Windows\System32即可注意,32位版本…

    2022年9月14日
    2
  • android短信验证码代码,Android短信验证码自动填写实现代码

    android短信验证码代码,Android短信验证码自动填写实现代码今天给大家分享一个Android短信验证码自动填写的功能。先看下效果图,我发送了一条短信到手机,自动填写验证码。如图:这个小功能运用到了观察者模式,什么是观察者模式?观察者模式:定义对象间的一种一个(Subject)对多(Observer)的依赖关系,当一个对象的状态发送改变时,所以依赖于它的对象都得到通知并被自动更新。在本例中,我们在短信中注册一个观察者,当短信功能(被观察者)收到信息时,就会…

    2022年7月25日
    9

发表回复

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

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