ARouter 源码解析

前言

最近使用了阿里的ARouter框架,现在来讲解一下自己关于ARouter源码的理解


一、ARouter 简介

1. 什么是ARouter

ARouter是由alibaba开源的一个帮助Android App进行组件化路由改造的路由框架。(Github地址)

2. ARouter框架的作用

  1. 路由:实现页面之间的跳转,包括外部URL跳转到内部页面,module之间页面跳转,可以监听跳转过程同时可以指定拦截器
  2. 通信:跳转时可以传递参数
  3. 解耦:跳转不再依赖具体的目标类,各个module之间耦合度降低

二、ARouter原理概述

ARouter功能的实现主要包含三个部分:1.配置和使用 2. 编译期 3. 运行时

1. 配置和使用

关于ARouter的使用方式,其实在GitHub中已经有很明确的介绍,我就不再赘述了。

2. 编译期原理分析

ARouter框架使用时主要用的三个编译期注解为@Route、@Interceptor、@Autowired,在代码的编译期间,利用APT(Annotation Processing Tool)工具生成路由表,对应的注解处理器分别为 RouteProcessor,InterceptorProcessor,AutowiredProcessor,都在arouter-compiler包中。他们都继承自BaseProcessor类,而BaseProcessor继承自AbstractProcessor类,利用Google的@AutoService(Processor.class)注解自动生成服务,当处于编译期间时,编译器会检测继承自AbstractProcessor的子类,调用子类的process()方法,并将包含注解的元素传递进来,然后经过分析后,使用JavaPoet生成java文件。

我们先看一下BaseProcessor类的关键方法,

BaseProcessor.java

//初始化方法,只会执行一次
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
   
    super.init(processingEnv);
   
    //用于生成.java文件
    mFiler = processingEnv.getFiler();
    //类型校验
    types = processingEnv.getTypeUtils();
    //元素校验
    elementUtils = processingEnv.getElementUtils();
    //类型工具类
    typeUtils = new TypeUtils(types, elementUtils);
    //封装了日志
    logger = new Logger(processingEnv.getMessager());

    // Attempt to get user configuration [moduleName]
    Map<String, String> options = processingEnv.getOptions();
    //读取我们在build.gradle中配置的信息
    if (MapUtils.isNotEmpty(options)) {
   
        moduleName = options.get(KEY_MODULE_NAME);
        generateDoc = VALUE_ENABLE.equals(options.get(KEY_GENERATE_DOC_NAME));
    }

    if (StringUtils.isNotEmpty(moduleName)) {
   
        moduleName = moduleName.replaceAll("[^0-9a-zA-Z_]+", "");
        logger.info("The user has configuration the module name, it was [" + moduleName + "]");
    } else {
   
        //如果没配置会报出异常
        logger.error(NO_MODULE_NAME_TIPS);
        throw new RuntimeException("ARouter::Compiler >>> No module name, for more information, look at gradle log.");
    }
}

@Override
public Set<String> getSupportedOptions() {
   
    //添加Option参数,在build.gradle中配置
    return new HashSet<String>() {
   {
   
        this.add(KEY_MODULE_NAME);
        this.add(KEY_GENERATE_DOC_NAME);
    }};
}

BaseProcessor中定义了一些基本的方法,下面我们通过RouteProcessor分析ARouter如何生成路由文件的。

RouteProcessor.java

@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
   
    super.init(processingEnv);
    //如果需要生成文档,初始化JavaFile对象,在build.gradle中配置
    if (generateDoc) {
   
        try {
   
            docWriter = mFiler.createResource(
                    StandardLocation.SOURCE_OUTPUT,
                    PACKAGE_OF_GENERATE_DOCS,
                    "arouter-map-of-" + moduleName + ".json"
            ).openWriter();
        } catch (IOException e) {
   
            logger.error("Create doc writer failed, because " + e.getMessage());
        }
    }
    ......
}

//会自动被编译器调用
@Override
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;
}

//解析数据,组合rootMap、groupMap,生成ARouter$$Group$$xxx,ARouter$$Providers$$xxx,ARouter$$Root$$xxx文件
private void parseRoutes(Set<? extends Element> routeElements) throws IOException {
   
    if (CollectionUtils.isNotEmpty(routeElements)) {
   
        rootMap.clear();
        
        TypeMirror type_Activity = elementUtils.getTypeElement(ACTIVITY).asType();
        TypeMirror type_Service = elementUtils.getTypeElement(SERVICE).asType();
        TypeMirror fragmentTm = elementUtils.getTypeElement(FRAGMENT).asType();
        TypeMirror fragmentTmV4 = elementUtils.getTypeElement(Consts.FRAGMENT_V4).asType();

        // Interface of ARouter
        TypeElement type_IRouteGroup = elementUtils.getTypeElement(IROUTE_GROUP);
        TypeElement type_IProviderGroup = elementUtils.getTypeElement(IPROVIDER_GROUP);
        ClassName routeMetaCn = ClassName.get(RouteMeta.class);
        ClassName routeTypeCn = ClassName.get(RouteType.class);

        //构建 Map<String, Class<? extends IRouteGroup>> 参数类型
        ParameterizedTypeName inputMapTypeOfRoot = ParameterizedTypeName.get(
                ClassName.get(Map.class),
                ClassName.get(String.class),
                ParameterizedTypeName.get(
                        ClassName.get(Class.class),
                        WildcardTypeName.subtypeOf(ClassName.get(type_IRouteGroup))
                )
        );

        //构建 Map<String, RouteMeta> 参数类型
        ParameterizedTypeName inputMapTypeOfGroup = ParameterizedTypeName.get(
                ClassName.get(Map.class),
                ClassName.get(String.class),
                ClassName.get(RouteMeta.class)
        );

		//构建com.alibaba.android.arouter.routes包下的
		//ARouter$$Group$$xxx,ARouter$$Providers$$xxx,ARouter$$Root$$xxx,三个文件的方法入参
        ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot, "routes").build();
        ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "atlas").build();
        ParameterSpec providerParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "providers").build();//构建ARouter$$Root$$xxx的loadInto方法
        MethodSpec.Builder loadIntoMethodOfRootBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
                .addAnnotation(Override.class)
                .addModifiers(PUBLIC)
                .addParameter(rootParamSpec);
                
		//for循环解析各种元素,生成不同的RouteMeta
        for (Element element : routeElements) {
   
            TypeMirror tm = element.asType();
            Route route = element.getAnnotation(Route.class);
            RouteMeta routeMeta;
            // Activity or Fragment
            if (types.isSubtype(tm, type_Activity) || types.isSubtype(tm, fragmentTm) || types.isSubtype(tm, fragmentTmV4)) {
   
                // Get all fields annotation by @Autowired
                Map<String, Integer> paramsType = new HashMap<>();
                Map<String, Autowired> injectConfig = new HashMap<>();
                injectParamCollector(element, paramsType, injectConfig);
                if (types.isSubtype(tm, type_Activity)) {
   
                    // Activity
                    routeMeta = new 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ByeMoon丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值