前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >arouter实现activity跳转原理

arouter实现activity跳转原理

作者头像
全栈程序员站长
发布2022-08-31 15:40:32
4430
发布2022-08-31 15:40:32
举报

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

一、思路分析

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

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

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

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

二、源码分析

1. 注解

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

代码语言:javascript
复制
//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下,自动生成的代码如下所示:

代码语言:javascript
复制
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,遍历执行添加到路由表的方法

代码语言:javascript
复制
//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来实现跳转。

代码语言:javascript
复制
//_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.cn/143535.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年5月2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、思路分析
  • 二、源码分析
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档