arouter实现activity跳转原理

一、思路分析

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

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

2. 通过扫描获取所有类,遍历自动执行步骤1中所生成地代码,从而路由表中有了对应地数据,路由表的数据结构为 Map> 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 annotations, RoundEnvironment roundEnv) {
        if (CollectionUtils.isNotEmpty(annotations)) {
            //获取 Route注解的所有节点
            Set 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 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(){{" + 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() {
            {
                this.put("key1", 8);
            }
        }, -1, -2147483648));
        atlas.put("/test/activity3", RouteMeta.build(RouteType.ACTIVITY, Test3Activity.class, "/test/activity3", "test", new HashMap() {
            {
                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原理官方文档

 

你可能感兴趣的:(源码,android,组件化)