Android-ARouter原理解析

一、ARouter

ARouter使用的是APT(Annotation Processing Tool)注解处理器,通过给对应的类添加注解,在编译器动态生成对应的路由表文件。这里以分析ARouter的RouteProcessor。在ARouter的使用配置上,需要给base库配置

dependencies {
    // Replace with the latest version   现在的最新版本是1.5.1
    compile 'com.alibaba:arouter-api:?'
    annotationProcessor 'com.alibaba:arouter-compiler:?'
    ...
}

然后给每个组件都配置annotationProcessor,如果使用kotlin,则使用kapt
接着给每个组件都配置上下面的内容:

android {
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AROUTER_MODULE_NAME: project.getName()]
            }
        }
    }
}

这个配置主要是通过这个annotationProcessorOptions获取到key为AROUTER_MODULE_NAME的值,这个值其实就是module的name,这个的作用就是作为一个Root文件的命名的,因为一个module中可能会有多个group,而多个group归属于一个Root,而ARouter的做法就是将一个module作为一个Root。

1.AbstractProcessor相关类说明

(1)Element

Element 是一个接口,它只在编译期存在和Type有区别,表示程序的一个元素,可以是package,class,interface,method,成员变量,函数参数,泛型类型等。

它的子类包括ExecutableElement, PackageElement, Parameterizable, QualifiedNameable, TypeElement, TypeParameterElement, VariableElement。

Element的子类介绍:

ExecutableElement:表示类或者接口中的方法,构造函数或者初始化器。

PackageElement :表示包程序元素

TypeELement:表示一个类或者接口元素

TypeParameterElement:表示类,接口,方法的泛型类型例如T。

VariableElement:表示字段,枚举常量,方法或者构造函数参数,局部变量,资源变量或者异常参数。

Element只在编译期可见

(2)相关函数

asType(): 返回TypeMirror,TypeMirror是元素的类型信息,包括包名,类(或方法,或参数)名/类型。TypeMirror的子类有ArrayType, DeclaredType, DisjunctiveType, ErrorType, ExecutableType, NoType, NullType, PrimitiveType, ReferenceType, TypeVariable, WildcardType ,getKind可以获取类型。

equals(Object obj): 比较两个Element利用equals方法。

getAnnotation(Class<A> annotationType): 传入注解可以获取该元素上的所有注解。

getAnnotationMirrors(): 获该元素上的注解类型。

getEnclosedElements(): 获取该元素上的直接子元素,类似一个类中有VariableElement。

getEnclosingElement(): 获取该元素的父元素,如果是PackageElement则返回null,如果是TypeElement则返回PackageElement,如果是TypeParameterElement则返回泛型Element

getKind():返回值为ElementKind,通过ElementKind可以知道是那种element,具体就是Element的那些子类。

getModifiers(): 获取修饰该元素的访问修饰符,public,private。

getSimpleName(): 获取元素名,不带包名,如果是变量,获取的就是变量名,如果是定义了int age,获取到的name就是age。如果是TypeElement返回的就是类名。

getQualifiedName():获取类的全限定名,Element没有这个方法它的子类有,例如TypeElement,得到的就是类的全类名(包名)。

2.源码分析—路由注解处理器

(1)BaseProcessor
public abstract class BaseProcessor extends AbstractProcessor {
    //文件生成器
    Filer mFiler;
    Logger logger;
    // 用于操作TypeMirror的工具类
    Types types;
    // 处理Element的工具类
    // 还可以用来获取对应的类(通过字符串全路径)获取对应的TypeElement等
    Elements elementUtils;
    // type工具类,里面有针对TypeMirror的工具Types和对应的序列化类
    TypeUtils typeUtils;
    // Module name, maybe its 'app' or others
    // 从options中取出每个module的name,这个moduleName的值,其实是在每个
    // module的build.gradle中进行配置的arguments = [AROUTER_MODULE_NAME: project.getName()]
    String moduleName = null;
    // If need generate router doc
    boolean generateDoc;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);

        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]
        // 这里就是从每个module中的build.gradle的annotationProcessorOptions配置中取出options数据
        // 需要使用组件化的module都需要配置该options,然后这个key对应的name就是moduleName
        Map<String, String> options = processingEnv.getOptions();
        if (MapUtils.isNotEmpty(options)) {
            moduleName = options.get(KEY_MODULE_NAME);
            generateDoc = VALUE_ENABLE.equals(options.get(KEY_GENERATE_DOC_NAME));
        }

        // 如果module中的build.gradle没有配置annotationProcessorOptions
        // 也就是无法取到对应的moduleName,则动态生成对应的moduleName
        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 SourceVersion getSupportedSourceVersion() {
        // 配置源码版本,其实就是JDK版本
        return SourceVersion.latestSupported();
    }

    @Override
    public Set<String> getSupportedOptions() {
        // 配置options的key
        // KEY_MODULE_NAME是一个字符串"AROUTER_MODULE_NAME"
        return new HashSet<String>() {{
            this.add(KEY_MODULE_NAME);
            this.add(KEY_GENERATE_DOC_NAME);
        }};
    }
}
(2)RouteProcessor

具体的注解处理流程如下:

1.准备条件判断和文件生成需要的类型和类名
2.创建Root和Group文件的方法参数类型名对象
3.定义Root和Group文件的loadInfo方法的参数对象,包括类型和参数名称
4.创建Root类文件的loadInfo方法的构建者对象(这里感觉可以在最后创建)
5.遍历所有元素,对元素进行分组,根据@Route传入的group进行分组,一组对应多个路由
6.定义Provider类文件的loadInfo方法
7.生成所有的Group类文件,这里与传统使用JavaPoet生成Java类文件略有不同,因为使用了接口的方式,所以定义TypeSpec和JavaFile组合进行
8.rootMap添加分组文件信息
9.遍历rootMap集合,添加使用与输出Group类文件同样的方式输出Root类文件

@AutoService(Processor.class)
@SupportedAnnotationTypes({ANNOTATION_TYPE_ROUTE, ANNOTATION_TYPE_AUTOWIRED})
public class RouteProcessor extends BaseProcessor {
    private Map<String, Set<RouteMeta>> groupMap = new HashMap<>(); // ModuleName and routeMeta.
    private Map<String, String> rootMap = new TreeMap<>();  // Map of root metas, used for generate class file in order.

    private TypeMirror iProvider = null;
    private Writer docWriter;       // Writer used for write doc

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);

        // 如果需要生成路由器文档,则创建对应的Writer对象
        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());
            }
        }

        // 获取IProvider类型
        iProvider = elementUtils.getTypeElement(Consts.IPROVIDER).asType();

        logger.info(">>> RouteProcessor init. <<<");
    }

    /**
     * {@inheritDoc}
     *
     * @param annotations
     * @param roundEnv
     */
    @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;
    }

    private void parseRoutes(Set<? extends Element> routeElements) throws IOException {
        if (CollectionUtils.isNotEmpty(routeElements)) {
            // prepare the type an so on.

            logger.info(">>> Found routes, size is " + routeElements.size() + " <<<");

            rootMap.clear();

            // 获取Activity、Service、Fragment和V4包下的Fragment的类型
            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
            // 获取ARouter相关的接口类型,一个是Root文件类实现的接口
            // 这里单独从静态常量中定义成一个TypeElement是因为不止被用于接口实现,还在Root类文件的方法参数中
            // 有一个Map集合参数,Map<String, Class<? extends IRouteGroup>> routes这里用到了这个Group类型
            TypeElement type_IRouteGroup = elementUtils.getTypeElement(IROUTE_GROUP);
            TypeElement type_IProviderGroup = elementUtils.getTypeElement(IPROVIDER_GROUP);

            // RouteMeta的ClassName,用于替换$T.build这里
            ClassName routeMetaCn = ClassName.get(RouteMeta.class);
            // RouteType的ClassName,用于替换RouteMeta.build($T.ACTIVITY)这里的$T
            ClassName routeTypeCn = ClassName.get(RouteType.class);

            /**
             * TODO:1.创建Root、Group类中的loadInfo方法的参数类型
             */
            /*
               Build input type, format as :

               ```Map<String, Class<? extends IRouteGroup>>```
             */
            // 这里创建的是Root文件的loadInfo方法的参数类型
            ParameterizedTypeName inputMapTypeOfRoot = ParameterizedTypeName.get(
                    ClassName.get(Map.class),
                    ClassName.get(String.class),
                    // Class<? extends IRouteGroup>
                    // 第一个参数就是Class,泛型因为是使用了extends,所以需要使用WildcardTypeName
                    ParameterizedTypeName.get(
                            ClassName.get(Class.class),
                            WildcardTypeName.subtypeOf(ClassName.get(type_IRouteGroup))
                    )
            );

            /*

              ```Map<String, RouteMeta>```
             */
            // 这里创建的是Group文件的loadInfo方法的参数类型
            ParameterizedTypeName inputMapTypeOfGroup = ParameterizedTypeName.get(
                    ClassName.get(Map.class),
                    ClassName.get(String.class),
                    ClassName.get(RouteMeta.class)
            );

            /**
             * TODO:2.定义Root、Group、Provider等类的loadInfo方法的参数
             */
            /*
              Build input param name.
             */
            // 定义要不同文件对应的loadInfo方法的参数名称
            // root文件的loadInfo方法的参数名称
            ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot, "routes").build();
            // group文件的loadInfo方法的参数名称
            ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "atlas").build();
            // provider文件的loadInfo方法的参数名称
            ParameterSpec providerParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "providers").build();  // Ps. its param type same as groupParamSpec!

            /**
             * TODO:3.生成对应的Root类的方法的Builder,但是这需要在最后使用
             */
            /*
              Build method : 'loadInto'
             */
            // 生成对应root文件的方法
            MethodSpec.Builder loadIntoMethodOfRootBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
                    .addAnnotation(Override.class)
                    .addModifiers(PUBLIC)
                    .addParameter(rootParamSpec);

            /**
             * TODO:4.遍历所有的元素,将元素进行分组
             * 分成多个的Group,每个Group有多个路由,即一个Group使用一个Key,对应一个Set集合的路由表
             * 最后进行一步排序
             */
            //  Follow a sequence, find out metas of group first, generate java file, then statistics them as root.
            // 首先找出每个组下对应的metas,然后再找将组统计为root
            for (Element element : routeElements) {
                // 获取使用Route注解的元素的类型,比如Activity、Fragment、Service、Provider等
                TypeMirror tm = element.asType();
                // 获取element的Route注解
                Route route = element.getAnnotation(Route.class);
                // 定义每个element对应的RouteMeta,其实就是保存在Group文件中的loadInfo方法的参数Map集合中的value
                RouteMeta routeMeta;

                // Activity or Fragment
                // 如果该元素是Activity或者Fragment类型
                if (types.isSubtype(tm, type_Activity) || types.isSubtype(tm, fragmentTm) || types.isSubtype(tm, fragmentTmV4)) {
                    // Get all fields annotation by @Autowired
                    // 获取该元素中所有被@Autowired注解的字段
                    // 用于保存在对应的Activity或者Fragment的封装类RouteMeta中
                    Map<String, Integer> paramsType = new HashMap<>();
                    Map<String, Autowired> injectConfig = new HashMap<>();
                    // 找出Activity或者Fragment类型的element中使用@Autowired注解的字段
                    // 包括其父类中的字段
                    // Autowired的key是对应的字段名
                    injectParamCollector(element, paramsType, injectConfig);

                    if (types.isSubtype(tm, type_Activity)) {
                        // Activity
                        logger.info(">>> Found activity route: " + tm.toString() + " <<<");
                        // 这里就给对应的路由设置了对应的类型,比如RouteType.ACTIVITY
                        // RouteType这个是枚举类型
                        // route是路由的path,element其实就是被@Route注释的类
                        // paramsType是所有的参数类型
                        routeMeta = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType);
                    } else {
                        // Fragment
                        logger.info(">>> Found fragment route: " + tm.toString() + " <<<");
                        routeMeta = new RouteMeta(route, element, RouteType.parse(FRAGMENT), paramsType);
                    }

                    routeMeta.setInjectConfig(injectConfig);
                } else if (types.isSubtype(tm, iProvider)) {         // IProvider
                    // 如果是IProvider类型
                    logger.info(">>> Found provider route: " + tm.toString() + " <<<");
                    routeMeta = new RouteMeta(route, element, RouteType.PROVIDER, null);
                } else if (types.isSubtype(tm, type_Service)) {           // Service
                    // 如果是Service类型
                    logger.info(">>> Found service route: " + tm.toString() + " <<<");
                    routeMeta = new RouteMeta(route, element, RouteType.parse(SERVICE), null);
                } else {
                    throw new RuntimeException("The @Route is marked on unsupported class, look at [" + tm.toString() + "].");
                }

                // 针对分组对路由进行排序
                // 将同组的路由保存在一个Set集合中,并且使用Group名作为key保存到对应的Map集合中
                categories(routeMeta);
            }

            /**
             * TODO:5.定义Provider对应的类的loadInfo方法
             */
            // 定义Provider的方法
            MethodSpec.Builder loadIntoMethodOfProviderBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
                    .addAnnotation(Override.class)
                    .addModifiers(PUBLIC)
                    .addParameter(providerParamSpec);

            Map<String, List<RouteDoc>> docSource = new HashMap<>();

            /**
             * TODO:6.生成所有的Group文件
             * 并且对所有的Group和GroupFile进行一一对应,保存在Map集合中
             */
            // Start generate java source, structure is divided into upper and lower levels, used for demand initialization.
            // 开始生产java文件,分成上下两层。
            // 从遍历整个root集合开始。groupMap其实就是整个root对应的所有路由表数据
            for (Map.Entry<String, Set<RouteMeta>> entry : groupMap.entrySet()) {
                // 获取分组名
                String groupName = entry.getKey();

                // 定义group文件的方法
                MethodSpec.Builder loadIntoMethodOfGroupBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
                        .addAnnotation(Override.class)// 定义对应的方法添加Override注解类
                        .addModifiers(PUBLIC)
                        .addParameter(groupParamSpec);

                List<RouteDoc> routeDocList = new ArrayList<>();

                // Build group method body
                // 取出该group分组中的所有路由,也就是一个分组数据
                Set<RouteMeta> groupData = entry.getValue();
                // 遍历所有的路由
                // TODO:遍历一个Group分组中的所有路由
                for (RouteMeta routeMeta : groupData) {
                    // 获取路由中的额外的文档信息
                    RouteDoc routeDoc = extractDocInfo(routeMeta);

                    // 获取路由的真实类型名称
                    ClassName className = ClassName.get((TypeElement) routeMeta.getRawType());

                    // 遍历路由类型,判断是Provider与否
                    switch (routeMeta.getType()) {
                        case PROVIDER:  // Need cache provider's super class
                            // 这里的routeMeta.getRawType()其实是一个Element
                            // 而实现了IProvider的,比如ARouter的demo中的HelloServiceImpl
                            // 被@Route注解的对应的接口实现类
                            // 然后获取到该element的所有实现的接口,包括父类的
                            // 接着遍历其实现的接口,遍历判断是否有实现了IProvider接口
                            List<? extends TypeMirror> interfaces = ((TypeElement) routeMeta.getRawType()).getInterfaces();
                            for (TypeMirror tm : interfaces) {
                                routeDoc.addPrototype(tm.toString());
                                // TODO: 在创建Provider文件的时候,其内部也会将对应的键值对数据保存在一个Map
                                // Provider文件其实就是类似Group文件,只不过Provider中的Map的key并不是path
                                // Provider中的Map的key,其实是直接实现或者继承了IProvider接口的类的全路径
                                // 如果该element直接实现了IProvider接口
                                if (types.isSameType(tm, iProvider)) {   // Its implements iProvider interface himself.
                                    // This interface extend the IProvider, so it can be used for mark provider
                                    loadIntoMethodOfProviderBuilder.addStatement(
                                            "providers.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, null, " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
                                            (routeMeta.getRawType()).toString(),
                                            routeMetaCn,
                                            routeTypeCn,
                                            className,// IProvider最终实现类型
                                            routeMeta.getPath(),
                                            routeMeta.getGroup());
                                } else if (types.isSubtype(tm, iProvider)) {
                                    // 如果是element其父类实现了IProvider接口
                                    // 比如HelloServiceImpl就是这个element,而实现了IProvider的是HelloService
                                    // This interface extend the IProvider, so it can be used for mark provider
                                    loadIntoMethodOfProviderBuilder.addStatement(
                                            "providers.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, null, " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
                                            tm.toString(),    // So stupid, will duplicate only save class name.
                                            routeMetaCn,
                                            routeTypeCn,
                                            className,// IProvider最终实现类型,比如HelloServiceImpl
                                            routeMeta.getPath(),
                                            routeMeta.getGroup());
                                }
                            }
                            break;
                        default:
                            break;
                    }

                    // Make map body for paramsType
                    StringBuilder mapBodyBuilder = new StringBuilder();
                    Map<String, Integer> paramsType = routeMeta.getParamsType();
                    Map<String, Autowired> injectConfigs = routeMeta.getInjectConfig();
                    if (MapUtils.isNotEmpty(paramsType)) {
                        List<RouteDoc.Param> paramList = new ArrayList<>();

                        for (Map.Entry<String, Integer> types : paramsType.entrySet()) {
                            mapBodyBuilder.append("put(\"").append(types.getKey()).append("\", ").append(types.getValue()).append("); ");

                            RouteDoc.Param param = new RouteDoc.Param();
                            Autowired injectConfig = injectConfigs.get(types.getKey());
                            param.setKey(types.getKey());
                            param.setType(TypeKind.values()[types.getValue()].name().toLowerCase());
                            param.setDescription(injectConfig.desc());
                            param.setRequired(injectConfig.required());

                            paramList.add(param);
                        }

                        routeDoc.setParams(paramList);
                    }
                    // 这里是每个path类中的使用了@Autowired注解的字段信息
                    String mapBody = mapBodyBuilder.toString();

                    // TODO:向Group类中添加一条路由信息
                    // 定义group文件的loadInfo方法的方法体
                    // 该group中的每个路由就添加一条方法体
                    // 即每一条方法体就是一个path信息
                    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(),// 替换第一个$S  这个字符串
                            routeMetaCn,// 这是RouteMeta的ClassName,用于替换$T.build中的这个$T
                            routeTypeCn,// RouteType的ClassName,用于替换build($T中的这个$T  其实就是RouteType.ACTIVITY或者RouteType.FRAGMENT
                            className,// 使用@Route注解的类的ClassName,替换$T.class中的这个$T
                            routeMeta.getPath().toLowerCase(),// 该路由的路径
                            routeMeta.getGroup().toLowerCase());// 该路由所在分组

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

                // TODO:输出Group分组文件
                // Generate groups
                // 输出group分组文件。一个分组输出一个分组文件
                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 + "<<<");

                // TODO:向rootMap中添加分组文件名与分组名的一一对应
                // for循环里每次都保存对应的groupFileName到对应的rootMap中
                rootMap.put(groupName, groupFileName);
                docSource.put(groupName, routeDocList);
            }

            /**
             * TODO:7.遍历rootMap,即遍历所有的分组
             * 向Root类中的loadInfo方法添加方法体,记录每一个Group信息,用于找到Group
             */
            if (MapUtils.isNotEmpty(rootMap)) {
                // Generate root meta by group name, it must be generated before root, then I can find out the class of group.
                for (Map.Entry<String, String> entry : rootMap.entrySet()) {
                    loadIntoMethodOfRootBuilder.addStatement("routes.put($S, $T.class)", entry.getKey(), ClassName.get(PACKAGE_OF_GENERATE_FILE, entry.getValue()));
                }
            }

            /**
             * TODO:8.输出doc文件
             */
            // Output route doc
            if (generateDoc) {
                docWriter.append(JSON.toJSONString(docSource, SerializerFeature.PrettyFormat));
                docWriter.flush();
                docWriter.close();
            }

            /**
             * TODO:9.输出provider类文件
             */
            // Write provider into disk
            // 输出provider相关的文件
            // Provider文件与Group文件是类似的,在查找的时候通过Autowired注解的对象类型的全路径名
            // 从对应的Warehouse.providersIndex缓存中找到对应的RouteMeta对象
            // 然后从RouteMeta中取出对应的IProvider接口的最终实现类型
            // 这个最终实现类型就是被@Route注解的IProvider接口实现类型
            String providerMapFileName = NAME_OF_PROVIDER + SEPARATOR + moduleName;
            JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
                    TypeSpec.classBuilder(providerMapFileName)
                            .addJavadoc(WARNING_TIPS)
                            .addSuperinterface(ClassName.get(type_IProviderGroup))
                            .addModifiers(PUBLIC)
                            .addMethod(loadIntoMethodOfProviderBuilder.build())
                            .build()
            ).build().writeTo(mFiler);

            logger.info(">>> Generated provider map, name is " + providerMapFileName + " <<<");

            /**
             * TODO:10.输出Root类文件
             */
            // Write root meta into disk.
            // 输出root文件用于找到对应的分组,其实就是保存分组的
            // 一个分组中有多个路由表
            String rootFileName = NAME_OF_ROOT + SEPARATOR + moduleName;
            JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
                    TypeSpec.classBuilder(rootFileName)
                            .addJavadoc(WARNING_TIPS)
                            .addSuperinterface(ClassName.get(elementUtils.getTypeElement(ITROUTE_ROOT)))
                            .addModifiers(PUBLIC)
                            .addMethod(loadIntoMethodOfRootBuilder.build())
                            .build()
            ).build().writeTo(mFiler);

            logger.info(">>> Generated root, name is " + rootFileName + " <<<");
        }
    }

    /**
     * Recursive inject config collector.
     *
     * @param element current element.
     */
    private void injectParamCollector(Element element, Map<String, Integer> paramsType, Map<String, Autowired> injectConfig) {
        for (Element field : element.getEnclosedElements()) {
            if (field.getKind().isField() && field.getAnnotation(Autowired.class) != null && !types.isSubtype(field.asType(), iProvider)) {
                // It must be field, then it has annotation, but it not be provider.
                Autowired paramConfig = field.getAnnotation(Autowired.class);
                String injectName = StringUtils.isEmpty(paramConfig.name()) ? field.getSimpleName().toString() : paramConfig.name();
                paramsType.put(injectName, typeUtils.typeExchange(field));
                injectConfig.put(injectName, paramConfig);
            }
        }

        // if has parent?
        TypeMirror parent = ((TypeElement) element).getSuperclass();
        if (parent instanceof DeclaredType) {
            Element parentElement = ((DeclaredType) parent).asElement();
            if (parentElement instanceof TypeElement && !((TypeElement) parentElement).getQualifiedName().toString().startsWith("android")) {
                injectParamCollector(parentElement, paramsType, injectConfig);
            }
        }
    }

    /**
     * Extra doc info from route meta
     *
     * @param routeMeta meta
     * @return doc
     */
    private RouteDoc extractDocInfo(RouteMeta routeMeta) {
        RouteDoc routeDoc = new RouteDoc();
        routeDoc.setGroup(routeMeta.getGroup());
        routeDoc.setPath(routeMeta.getPath());
        routeDoc.setDescription(routeMeta.getName());
        routeDoc.setType(routeMeta.getType().name().toLowerCase());
        routeDoc.setMark(routeMeta.getExtra());

        return routeDoc;
    }

    /**
     * Sort metas in group.
     * 将分组的路由信息进行排序,按照path进行排序
     * @param routeMete metas.
     */
    private void categories(RouteMeta routeMete) {
        // 排序的时候,首先沿着路由的合法性
        // 其实就是向RouteMeta中设置路由,如果@Route注解的group没有值
        // 则从path中取出第一段作为路由
        if (routeVerify(routeMete)) {
            logger.info(">>> Start categories, group = " + routeMete.getGroup() + ", path = " + routeMete.getPath() + " <<<");
            Set<RouteMeta> routeMetas = groupMap.get(routeMete.getGroup());
            if (CollectionUtils.isEmpty(routeMetas)) {
                Set<RouteMeta> routeMetaSet = new TreeSet<>(new Comparator<RouteMeta>() {
                    @Override
                    public int compare(RouteMeta r1, RouteMeta r2) {
                        try {
                            return r1.getPath().compareTo(r2.getPath());
                        } catch (NullPointerException npe) {
                            logger.error(npe.getMessage());
                            return 0;
                        }
                    }
                });
                routeMetaSet.add(routeMete);
                groupMap.put(routeMete.getGroup(), routeMetaSet);
            } else {
                routeMetas.add(routeMete);
            }
        } else {
            logger.warning(">>> Route meta verify error, group is " + routeMete.getGroup() + " <<<");
        }
    }

    /**
     * Verify the route meta
     * 验证路由的合法性
     * @param meta raw meta
     */
    private boolean routeVerify(RouteMeta meta) {
        String path = meta.getPath();

        if (StringUtils.isEmpty(path) || !path.startsWith("/")) {   // The path must be start with '/' and not empty!
            return false;
        }

        if (StringUtils.isEmpty(meta.getGroup())) { // Use default group(the first word in path)
            try {
                String defaultGroup = path.substring(1, path.indexOf("/", 1));
                if (StringUtils.isEmpty(defaultGroup)) {
                    return false;
                }

                meta.setGroup(defaultGroup);
                return true;
            } catch (Exception e) {
                logger.error("Failed to extract default group! " + e.getMessage());
                return false;
            }
        }

        return true;
    }
}

3.属性注入注解处理器AutowiredProcessor

首先,看下属性注解处理器生成的文件示例:

public class Test1Activity$$ARouter$$Autowired implements ISyringe {
  private SerializationService serializationService;

  @Override
  public void inject(Object target) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    Test1Activity substitute = (Test1Activity)target;
    substitute.age = substitute.getIntent().getIntExtra("age", substitute.age);
    substitute.height = substitute.getIntent().getIntExtra("height", substitute.height);
    substitute.girl = substitute.getIntent().getBooleanExtra("boy", substitute.girl);
    substitute.ch = substitute.getIntent().getCharExtra("ch", substitute.ch);
    substitute.fl = substitute.getIntent().getFloatExtra("fl", substitute.fl);
    substitute.dou = substitute.getIntent().getDoubleExtra("dou", substitute.dou);
    substitute.ser = (com.alibaba.android.arouter.demo.service.model.TestSerializable) substitute.getIntent().getSerializableExtra("ser");
    substitute.pac = substitute.getIntent().getParcelableExtra("pac");
    if (null != serializationService) {
      substitute.obj = serializationService.parseObject(substitute.getIntent().getStringExtra("obj"), new com.alibaba.android.arouter.facade.model.TypeWrapper<TestObj>(){}.getType());
    } else {
      Log.e("ARouter::", "You want automatic inject the field 'obj' in class 'Test1Activity' , then you should implement 'SerializationService' to support object auto inject!");
    }
    if (null != serializationService) {
      substitute.objList = serializationService.parseObject(substitute.getIntent().getStringExtra("objList"), new com.alibaba.android.arouter.facade.model.TypeWrapper<List<TestObj>>(){}.getType());
    } else {
      Log.e("ARouter::", "You want automatic inject the field 'objList' in class 'Test1Activity' , then you should implement 'SerializationService' to support object auto inject!");
    }
    if (null != serializationService) {
      substitute.map = serializationService.parseObject(substitute.getIntent().getStringExtra("map"), new com.alibaba.android.arouter.facade.model.TypeWrapper<Map<String, List<TestObj>>>(){}.getType());
    } else {
      Log.e("ARouter::", "You want automatic inject the field 'map' in class 'Test1Activity' , then you should implement 'SerializationService' to support object auto inject!");
    }
    substitute.url = substitute.getIntent().getExtras() == null ? substitute.url : substitute.getIntent().getExtras().getString("url", substitute.url);
    substitute.helloService = ARouter.getInstance().navigation(HelloService.class);
  }
}
(1)AutowiredProcessor源码解析

AutowiredProcessor这个注解处理器的目的,就是通过这个注解处理器给对应的类中的属性进行赋值的操作。
AutowiredProcessor注解处理器流程:

1.首先对资源进行分组,按类分组,一个类包含多个使用了@Autowired注解的字段
2.创建每个注解处理器生成的类中的inject函数的参数,是Object类型,名为target
3.创建每个分组生成的java类对应的函数,方法名是inject
4.初始化创建类的数据,包括创建类需要的包名和类名等信息
5.创建每个分组对应的TypeSpec,这里创建的类需要实现ISyringe接口
6.向类中添加属性,即SerializationService对象,用以解析如Object、List、Map等类型数据
7.创建对应的statement的字符串结构,根据statement字符串进行不同的addStatement操作
8.创建JavaFile,生成对应的文件

@AutoService(Processor.class)
@SupportedAnnotationTypes({ANNOTATION_TYPE_AUTOWIRED})
public class AutowiredProcessor extends BaseProcessor {
    private Map<TypeElement, List<Element>> parentAndChild = new HashMap<>();   // Contain field need autowired and his super class.
    private static final ClassName ARouterClass = ClassName.get("com.alibaba.android.arouter.launcher", "ARouter");
    private static final ClassName AndroidLog = ClassName.get("android.util", "Log");

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);

        logger.info(">>> AutowiredProcessor init. <<<");
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        if (CollectionUtils.isNotEmpty(set)) {
            try {
                logger.info(">>> Found autowired field, start... <<<");
                // 获取所有被@Autowired注解的元素,根据其类元素作为一组,进行分组保存
                // 这里的分组,父类和子类是分开的分组,子类中不会包含父类的
                categories(roundEnvironment.getElementsAnnotatedWith(Autowired.class));
                generateHelper();

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

        return false;
    }

    private void generateHelper() throws IOException, IllegalAccessException {
        // 这是生成的Java类需要实现的接口类型
        TypeElement type_ISyringe = elementUtils.getTypeElement(ISYRINGE);
        // 这是用于操作对象、列表、map等数据的处理类
        TypeElement type_JsonService = elementUtils.getTypeElement(JSON_SERVICE);
        // 获取对应的IProvider、Activity、Fragment、Fragment_V4的TypeMirror
        // 其实就是对应的类元素的类型信息
        TypeMirror iProvider = elementUtils.getTypeElement(Consts.IPROVIDER).asType();
        TypeMirror activityTm = elementUtils.getTypeElement(Consts.ACTIVITY).asType();
        TypeMirror fragmentTm = elementUtils.getTypeElement(Consts.FRAGMENT).asType();
        TypeMirror fragmentTmV4 = elementUtils.getTypeElement(Consts.FRAGMENT_V4).asType();

        // Build input param name.     public void inject(Object target)
        // 定义方法的参数类型和名称,即Object类型,参数名是target
        ParameterSpec objectParamSpec = ParameterSpec.builder(TypeName.OBJECT, "target").build();

        // 如果分组集合不为null,则遍历所有的分组数据
        // 根据每个分组,生成对应的Java文件
        if (MapUtils.isNotEmpty(parentAndChild)) {
            for (Map.Entry<TypeElement, List<Element>> entry : parentAndChild.entrySet()) {
                // Build method : 'inject'
                // 创建对应的java文件中的方法的Builder,方法名是inject,参数是前面创建的Object类型的名为target
                MethodSpec.Builder injectMethodBuilder = MethodSpec.methodBuilder(METHOD_INJECT)
                        .addAnnotation(Override.class)
                        .addModifiers(PUBLIC)
                        .addParameter(objectParamSpec);

                // 这里的parent其实就是对应的使用@Autowired注解的字段所在的类
                TypeElement parent = entry.getKey();
                // childs其实就是该类中所有被@Autowired注解的字段集合
                List<Element> childs = entry.getValue();

                // 获取该类的全路径名(包名+类名)
                String qualifiedName = parent.getQualifiedName().toString();
                // 获取该类的包名路径(包名)
                String packageName = qualifiedName.substring(0, qualifiedName.lastIndexOf("."));
                // 定义该类对应的生成的类的文件名(即生成类的类名)
                String fileName = parent.getSimpleName() + NAME_OF_AUTOWIRED;

                logger.info(">>> Start process " + childs.size() + " field in " + parent.getSimpleName() + " ... <<<");

                // 定义要生成的类的TypeSpec的Builder
                TypeSpec.Builder helper = TypeSpec.classBuilder(fileName)
                        .addJavadoc(WARNING_TIPS)
                        .addSuperinterface(ClassName.get(type_ISyringe))
                        .addModifiers(PUBLIC);

                // 定义类中的字段属性,即SerializationService对象
                FieldSpec jsonServiceField = FieldSpec.builder(TypeName.get(type_JsonService.asType()), "serializationService", Modifier.PRIVATE).build();
                // 给要生成的类添加属性
                helper.addField(jsonServiceField);

                // 在方法中对该属性进行初始化   serializationService = ARouter.getInstance().navigation(SerializationService.class);
                // ARouterClass是com.alibaba.android.arouter.launcher包下的ARouter类
                injectMethodBuilder.addStatement("serializationService = $T.getInstance().navigation($T.class)", ARouterClass, ClassName.get(type_JsonService));
                // 将inject的参数转成对应的@Autowired注解的属性所在的类类型,比如Test1Activity
                injectMethodBuilder.addStatement("$T substitute = ($T)target", ClassName.get(parent), ClassName.get(parent));

                // Generate method body, start inject.
                // 遍历该元素类中的所有被@Autowired注解注解的字段
                for (Element element : childs) {
                    Autowired fieldConfig = element.getAnnotation(Autowired.class);
                    // 获取被@Autowired注解的字段名
                    String fieldName = element.getSimpleName().toString();
                    // 判断被@Autowired注解的字段类型是否是IProvider接口子类型
                    if (types.isSubtype(element.asType(), iProvider)) {  // It's provider
                        // 如果是IProvider的实现类型,则通过ARouter.getInstance().navigation(元素类型)获取
                        if ("".equals(fieldConfig.name())) {    // User has not set service path, then use byType.

                            // Getter
                            injectMethodBuilder.addStatement(
                                    "substitute." + fieldName + " = $T.getInstance().navigation($T.class)",
                                    ARouterClass,
                                    ClassName.get(element.asType())
                            );
                        } else {    // use byName
                            // Getter
                            injectMethodBuilder.addStatement(
                                    "substitute." + fieldName + " = ($T)$T.getInstance().build($S).navigation()",
                                    ClassName.get(element.asType()),
                                    ARouterClass,
                                    fieldConfig.name()
                            );
                        }

                        // Validator
                        if (fieldConfig.required()) {
                            injectMethodBuilder.beginControlFlow("if (substitute." + fieldName + " == null)");
                            injectMethodBuilder.addStatement(
                                    "throw new RuntimeException(\"The field '" + fieldName + "' is null, in class '\" + $T.class.getName() + \"!\")", ClassName.get(parent));
                            injectMethodBuilder.endControlFlow();
                        }
                    } else {    // It's normal intent value
                        // 如果是正常的Intent的值
                        String originalValue = "substitute." + fieldName;
                        String statement = "substitute." + fieldName + " = " + buildCastCode(element) + "substitute.";
                        boolean isActivity = false;
                        if (types.isSubtype(parent.asType(), activityTm)) {  // Activity, then use getIntent()
                            isActivity = true;
                            statement += "getIntent().";
                        } else if (types.isSubtype(parent.asType(), fragmentTm) || types.isSubtype(parent.asType(), fragmentTmV4)) {   // Fragment, then use getArguments()
                            statement += "getArguments().";
                        } else {
                            throw new IllegalAccessException("The field [" + fieldName + "] need autowired from intent, its parent must be activity or fragment!");
                        }

                        statement = buildStatement(originalValue, statement, typeUtils.typeExchange(element), isActivity, isKtClass(parent));
                        if (statement.startsWith("serializationService.")) {   // Not mortals
                            injectMethodBuilder.beginControlFlow("if (null != serializationService)");
                            injectMethodBuilder.addStatement(
                                    "substitute." + fieldName + " = " + statement,
                                    (StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name()),
                                    ClassName.get(element.asType())
                            );
                            injectMethodBuilder.nextControlFlow("else");
                            injectMethodBuilder.addStatement(
                                    "$T.e(\"" + Consts.TAG + "\", \"You want automatic inject the field '" + fieldName + "' in class '$T' , then you should implement 'SerializationService' to support object auto inject!\")", AndroidLog, ClassName.get(parent));
                            injectMethodBuilder.endControlFlow();
                        } else {
                            injectMethodBuilder.addStatement(statement, StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name());
                        }

                        // Validator
                        if (fieldConfig.required() && !element.asType().getKind().isPrimitive()) {  // Primitive wont be check.
                            injectMethodBuilder.beginControlFlow("if (null == substitute." + fieldName + ")");
                            injectMethodBuilder.addStatement(
                                    "$T.e(\"" + Consts.TAG + "\", \"The field '" + fieldName + "' is null, in class '\" + $T.class.getName() + \"!\")", AndroidLog, ClassName.get(parent));
                            injectMethodBuilder.endControlFlow();
                        }
                    }
                }

                helper.addMethod(injectMethodBuilder.build());

                // Generate autowire helper
                JavaFile.builder(packageName, helper.build()).build().writeTo(mFiler);

                logger.info(">>> " + parent.getSimpleName() + " has been processed, " + fileName + " has been generated. <<<");
            }

            logger.info(">>> Autowired processor stop. <<<");
        }
    }
    ...
    /**
     * Categories field, find his papa.
     *
     * @param elements Field need autowired
     */
    private void categories(Set<? extends Element> elements) throws IllegalAccessException {
        if (CollectionUtils.isNotEmpty(elements)) {
            // 如果元素集合不为null,则遍历元素集合
            for (Element element : elements) {
                // getEnclosingElement() 获取该元素的父元素,如果是PackageElement则返回null,
                // 如果是TypeElement则返回PackageElement,如果是TypeParameterElement则返回泛型Element
                // 这里是类中的字段,getEnclosingElement会获取父元素,应该就是获取该字段所在的类元素
                TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();

                // 如果元素使用了private关键字变成私有的,则抛出异常
                if (element.getModifiers().contains(Modifier.PRIVATE)) {
                    throw new IllegalAccessException("The inject fields CAN NOT BE 'private'!!! please check field ["
                            + element.getSimpleName() + "] in class [" + enclosingElement.getQualifiedName() + "]");
                }

                // 根据类元素保存对应的所有被@Autowired注解的字段元素
                if (parentAndChild.containsKey(enclosingElement)) { // Has categries
                    parentAndChild.get(enclosingElement).add(element);
                } else {
                    List<Element> childs = new ArrayList<>();
                    childs.add(element);
                    parentAndChild.put(enclosingElement, childs);
                }
            }

            logger.info("categories finished.");
        }
    }

二、ARouter路由原理

ARouter在通过注解处理器生成对应的类文件之后,具体的路由执行操作,都是依赖于ARouter、_ARouter和Postcard等。这里的源码分析,还是基于ARouter的1.5.1的源码进行。

1.首先看具体使用的代码

@Route(path = "/test/activity1", name = "测试用 Activity")
public class Test1Activity extends BaseActivity {
    @Autowired
    int age = 10;

    @Autowired
    int height = 175;

    @Autowired(name = "boy", required = true)
    boolean girl;

    @Autowired
    char ch = 'A';

    @Autowired
    float fl = 12.00f;

    @Autowired
    double dou = 12.01d;

    @Autowired
    TestSerializable ser;

    @Autowired
    TestParcelable pac;

    @Autowired
    TestObj obj;

    @Autowired
    List<TestObj> objList;

    @Autowired
    Map<String, List<TestObj>> map;

    private long high;

    @Autowired
    String url;

    @Autowired
    HelloService helloService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test1);

        // 通过调用ARouter.getInstance().inject()获取到对应的Test1Activity
        // 的Test1Activity$$ARouter$$Autowired,注入对应的属性值
        // TODO:这里属性值的注入,还是需要先借助于AutowiredService这个服务来处理ISyringe
        ARouter.getInstance().inject(this);

        // No more getter ...
        // name = getIntent().getStringExtra("name");
        // age = getIntent().getIntExtra("age", 0);
        // girl = getIntent().getBooleanExtra("girl", false);
        // high = getIntent().getLongExtra("high", 0);
        // url = getIntent().getStringExtra("url");

        String params = String.format(
                "name=%s,\n age=%s, \n height=%s,\n girl=%s,\n high=%s,\n url=%s,\n ser=%s,\n pac=%s,\n obj=%s \n ch=%s \n fl = %s, \n dou = %s, \n objList=%s, \n map=%s",
                name,
                age,
                height,
                girl,
                high,
                url,
                ser,
                pac,
                obj,
                ch,
                fl,
                dou,
                objList,
                map
        );
        helloService.sayHello("Hello moto.");

        ((TextView) findViewById(R.id.test)).setText("I am " + Test1Activity.class.getName());
        ((TextView) findViewById(R.id.test2)).setText(params);
    }
}

上面的是目标Activity,而要跳转到该Activity,则需要通过调用ARouter来进行。

                ARouter.getInstance().build("/test/activity1")
                        .withString("name", "老王")
                        .withInt("age", 18)
                        .withBoolean("boy", true)
                        .withLong("high", 180)
                        .withString("url", "https://a.b.c")
                        .withSerializable("ser", testSerializable)
                        .withParcelable("pac", testParcelable)
                        .withObject("obj", testObj)
                        .withObject("objList", objList)
                        .withObject("map", map)
                        .navigation();

2.分析路由原理

(1)ARouter.build()方法

ARouter.build方法其实就是创建一个Postcard对象,该对象主要就是用来保存对应的页面调整所需要的参数和数据的。而ARouter的操作基本都是交给_ARouter来进行,所以这里ARouter.build的方法其实也是调用了_ARouter的build方法
看_ARouter.build方法的实现
这里因为我们并没使用PathReplaceService这个路径替换的服务,所以忽略这部分判断,直接返回一个Postcard对象,在Postcard对象中保存path和group

    protected Postcard build(String path, String group, Boolean afterReplace) {
        if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
            throw new HandlerException(Consts.TAG + "Parameter is invalid!");
        } else {
            if (!afterReplace) {
                PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
                if (null != pService) {
                    path = pService.forString(path);
                }
            }
            return new Postcard(path, group);
        }
    }
(2)Postcard的with方法

Postcard的with方法,以下面三个为例:
Postcard.withString

    public Postcard withString(@Nullable String key, @Nullable String value) {
        mBundle.putString(key, value);
        return this;
    }

Postcard.withSerializable

    public Postcard withSerializable(@Nullable String key, @Nullable Serializable value) {
        mBundle.putSerializable(key, value);
        return this;
    }

Postcard.withObject

    public Postcard withObject(@Nullable String key, @Nullable Object value) {
        serializationService = ARouter.getInstance().navigation(SerializationService.class);
        mBundle.putString(key, serializationService.object2Json(value));
        return this;
    }

其实Postcard的with方法中,只有withObject比较特殊,其他的都是常规的向Bundle添加数据。在withObject中使用到了SerializationService,其实现类只有一个JsonServiceImpl。

@Route(path = "/yourservicegroupname/json")
public class JsonServiceImpl implements SerializationService {
    @Override
    public void init(Context context) {

    }

    @Override
    public <T> T json2Object(String text, Class<T> clazz) {
        return JSON.parseObject(text, clazz);
    }

    @Override
    public String object2Json(Object instance) {
        return JSON.toJSONString(instance);
    }

    @Override
    public <T> T parseObject(String input, Type clazz) {
        return JSON.parseObject(input, clazz);
    }
}

从这里我们可以看出,JsonServiceImpl也是使用了路由的,这里可以使用路由的原因,其实就是SerializationService接口继承了IProvider,而ARouter会对实现了IProvider的类进行注解处理,从而也会生成对应的IProvider文件。这类文件主要是用来提供功能支持。所以SerializationService实现类对象可以通过ARouter.getInstance().navigation(SerializationService.class);来获取。
而withObject,其实就是将Object数据转换成Json字符串进行传递

(3)Postcard.navigation()
    public Object navigation() {
        return navigation(null);
    }

    /**
     * Navigation to the route with path in postcard.
     *
     * @param context Activity and so on.
     */
    public Object navigation(Context context) {
        return navigation(context, null);
    }

    /**
     * Navigation to the route with path in postcard.
     *
     * @param context Activity and so on.
     */
    public Object navigation(Context context, NavigationCallback callback) {
        return ARouter.getInstance().navigation(context, this, -1, callback);
    }
    /**
     * Navigation to the route with path in postcard.
     *
     * @param mContext    Activity and so on.
     * @param requestCode startActivityForResult's param
     */
    public void navigation(Activity mContext, int requestCode) {
        navigation(mContext, requestCode, null);
    }

    /**
     * Navigation to the route with path in postcard.
     *
     * @param mContext    Activity and so on.
     * @param requestCode startActivityForResult's param
     */
    public void navigation(Activity mContext, int requestCode, NavigationCallback callback) {
        ARouter.getInstance().navigation(mContext, this, requestCode, callback);
    }

Postcard中的navigation方法,有多个重载,可以支持使用requestCode,如果是无参的navigation()的话,则是使用applicationContext,其他的则需要自己传入context。
Postcard的navigation方法,其实最终就是调用到了_ARouter.navigation()方法
ARouter.navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback)

    public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) {
        return _ARouter.getInstance().navigation(mContext, postcard, requestCode, callback);
    }
(4)_ARouter.navigation

_ARouter.navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback)

    protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
        PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);
        if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {
            // Pretreatment failed, navigation canceled.
            return null;
        }

        // Set context to postcard.
        postcard.setContext(null == context ? mContext : context);

        try {
            // 这里是将路由和分组添加到一个缓存中
            // 下次取用的时候直接从这个缓存中获取,而不需要再去创建对应的生成的java文件对象
            LogisticsCenter.completion(postcard);
        } catch (NoRouteFoundException ex) {
            logger.warning(Consts.TAG, ex.getMessage());

            if (debuggable()) {
                // Show friendly tips for user.
                runInMainThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(mContext, "There's no route matched!\n" +
                                " Path = [" + postcard.getPath() + "]\n" +
                                " Group = [" + postcard.getGroup() + "]", Toast.LENGTH_LONG).show();
                    }
                });
            }

            if (null != callback) {
                callback.onLost(postcard);
            } else {
                // No callback for this invoke, then we use the global degrade service.
                DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
                if (null != degradeService) {
                    degradeService.onLost(context, postcard);
                }
            }

            return null;
        }

        if (null != callback) {
            callback.onFound(postcard);
        }

        if (!postcard.isGreenChannel()) {   // It must be run in async thread, maybe interceptor cost too mush time made ANR.
            interceptorService.doInterceptions(postcard, new InterceptorCallback() {
                /**
                 * Continue process
                 *
                 * @param postcard route meta
                 */
                @Override
                public void onContinue(Postcard postcard) {
                    _navigation(postcard, requestCode, callback);
                }

                /**
                 * Interrupt process, pipeline will be destory when this method called.
                 *
                 * @param exception Reson of interrupt.
                 */
                @Override
                public void onInterrupt(Throwable exception) {
                    if (null != callback) {
                        callback.onInterrupt(postcard);
                    }

                    logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " + exception.getMessage());
                }
            });
        } else {
            return _navigation(postcard, requestCode, callback);
        }

        return null;
    }

最后具体的跳转页面的实现,则是在_ARouter._navigation方法中。

(5)LogisticsCenter.completion

这里其实就是缓存对应的路由,将对应的path和RouteMeta通过调用对应的路由类进行缓存,避免多次创建路由类对象。
并且添加对应的目标Class等信息到Postcard中。

    public synchronized static void completion(Postcard postcard) {
        if (null == postcard) {
            throw new NoRouteFoundException(TAG + "No postcard!");
        }

        RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
        if (null == routeMeta) {
            // Maybe its does't exist, or didn't load.
            // Warehouse.groupsIndex是在LogisticsCenter调用init方法初始化的时候添加分组信息缓存的
            if (!Warehouse.groupsIndex.containsKey(postcard.getGroup())) {
                throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
            } else {
                // Load route and cache it into memory, then delete from metas.
                // 加载路由信息到缓存中
                try {
                    if (ARouter.debuggable()) {
                        logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] starts loading, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
                    }

                    addRouteGroupDynamic(postcard.getGroup(), null);

                    if (ARouter.debuggable()) {
                        logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] has already been loaded, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
                    }
                } catch (Exception e) {
                    throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
                }

                // 重新加载的目的就是为了在路由缓存中无数据的时候
                // 先加载缓存,然后再根据path将对应的路由信息加入到postcard中
                completion(postcard);   // Reload
            }
        } else {
            // 添加目标Class
            postcard.setDestination(routeMeta.getDestination());
            // 添加目标类型,比如ACTIVITY、FRAGMENT、SERVICE
            postcard.setType(routeMeta.getType());
            postcard.setPriority(routeMeta.getPriority());
            // 添加Extra
            postcard.setExtra(routeMeta.getExtra());

            Uri rawUri = postcard.getUri();
            if (null != rawUri) {   // Try to set params into bundle.
                Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);
                Map<String, Integer> paramsType = routeMeta.getParamsType();

                if (MapUtils.isNotEmpty(paramsType)) {
                    // Set value by its type, just for params which annotation by @Param
                    for (Map.Entry<String, Integer> params : paramsType.entrySet()) {
                        setValue(postcard,
                                params.getValue(),
                                params.getKey(),
                                resultMap.get(params.getKey()));
                    }

                    // Save params name which need auto inject.
                    postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
                }

                // Save raw uri
                postcard.withString(ARouter.RAW_URI, rawUri.toString());
            }

            switch (routeMeta.getType()) {
                case PROVIDER:  // if the route is provider, should find its instance
                    // Its provider, so it must implement IProvider
                    // Its provider, so it must implement IProvider
                    // 如果是Provider,则是从Provider文件中取出对应的RouteMeta对象
                    // 而在RouteMeta对象中,会保存对应的Provider.class
                    // 取出Provider.class进行初始化,保存在Warehouse.providers中
                    // 接着保存在对应的Postcard中,这个Postcard其实是用来保存获取Provider的了
                    Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
                    IProvider instance = Warehouse.providers.get(providerMeta);
                    if (null == instance) { // There's no instance of this provider
                        IProvider provider;
                        try {
                            provider = providerMeta.getConstructor().newInstance();
                            provider.init(mContext);
                            Warehouse.providers.put(providerMeta, provider);
                            instance = provider;
                        } catch (Exception e) {
                            throw new HandlerException("Init provider failed! " + e.getMessage());
                        }
                    }
                    postcard.setProvider(instance);
                    postcard.greenChannel();    // Provider should skip all of interceptors
                    break;
                case FRAGMENT:
                    postcard.greenChannel();    // Fragment needn't interceptors
                default:
                    break;
            }
        }
    }
(6)LogisticsCenter.addRouteGroupDynamic
    public synchronized static void addRouteGroupDynamic(String groupName, IRouteGroup group) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        if (Warehouse.groupsIndex.containsKey(groupName)){
            // If this group is included, but it has not been loaded
            // load this group first, because dynamic route has high priority.
            // 如果分组信息缓存中存在对应的分组
            // 那么就初始化该分组生成的对应Group类文件,然后向路由缓存中添加路由信息
            Warehouse.groupsIndex.get(groupName).getConstructor().newInstance().loadInto(Warehouse.routes);
            Warehouse.groupsIndex.remove(groupName);
        }

        // cover old group.
        // 这里的目的,是因为ARouter可以动态添加路由信息
        // 即采用主动的接口实现类的方式,实现IRouteGroup接口,然后做路由添加的操作
        if (null != group) {
            // 这里就是调用group分组的loadInfo方法,向Warehouse.routes缓存中添加对应的键值对
            // key是path,value是RouteMeta
            group.loadInto(Warehouse.routes);
        }
    }
(7)_ARouter._navigation
    private Object _navigation(final Postcard postcard, final int requestCode, final NavigationCallback callback) {
        final Context currentContext = postcard.getContext();

        switch (postcard.getType()) {
            case ACTIVITY:
                // Build intent
                final Intent intent = new Intent(currentContext, postcard.getDestination());
                intent.putExtras(postcard.getExtras());

                // Set flags.
                int flags = postcard.getFlags();
                if (0 != flags) {
                    intent.setFlags(flags);
                }

                // Non activity, need FLAG_ACTIVITY_NEW_TASK
                if (!(currentContext instanceof Activity)) {
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                }

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

                // Navigation in main looper.
                runInMainThread(new Runnable() {
                    @Override
                    public void run() {
                        startActivity(requestCode, currentContext, intent, postcard, callback);
                    }
                });

                break;
            case PROVIDER:
                return postcard.getProvider();
            case BOARDCAST:
            case CONTENT_PROVIDER:
            case FRAGMENT:
                Class<?> fragmentMeta = postcard.getDestination();
                try {
                    Object instance = fragmentMeta.getConstructor().newInstance();
                    if (instance instanceof Fragment) {
                        ((Fragment) instance).setArguments(postcard.getExtras());
                    } else if (instance instanceof android.support.v4.app.Fragment) {
                        ((android.support.v4.app.Fragment) instance).setArguments(postcard.getExtras());
                    }

                    return instance;
                } catch (Exception ex) {
                    logger.error(Consts.TAG, "Fetch fragment instance error, " + TextUtils.formatStackTrace(ex.getStackTrace()));
                }
            case METHOD:
            case SERVICE:
            default:
                return null;
        }

        return null;
    }
(8)LogisticsCenter.init

在LogisticsCenter.init初始化函数,是由_Arouter.init中进行初始化的,而_ARouter.init是在ARouter.init中进行初始化的。在LogisticsCenter.init中就会遍历所有的Root、Group、Provider、Interceptor文件,将对应的查找数据添加到缓存中,然后每次对实际的group、path对应的数据的查找都是从缓存中进行查找。

    public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
        mContext = context;
        executor = tpe;

        try {
            long startInit = System.currentTimeMillis();
            //load by plugin first
            loadRouterMap();
            if (registerByPlugin) {
                logger.info(TAG, "Load router map by arouter-auto-register plugin.");
            } else {
                Set<String> routerMap;

                // It will rebuild router map every times when debuggable.
                if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
                    logger.info(TAG, "Run with debug mode or new install, rebuild router map.");
                    // These class was generated by arouter-compiler.
                    routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
                    if (!routerMap.isEmpty()) {
                        context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();
                    }

                    PackageUtils.updateVersion(context);    // Save new version name when router map update finishes.
                } else {
                    logger.info(TAG, "Load router map from cache.");
                    routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
                }

                logger.info(TAG, "Find router map finished, map size = " + routerMap.size() + ", cost " + (System.currentTimeMillis() - startInit) + " ms.");
                startInit = System.currentTimeMillis();

                for (String className : routerMap) {
                    if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
                        // This one of root elements, load root.
                        ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
                    } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
                        // Load interceptorMeta
                        ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
                    } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
                        // Load providerIndex
                        ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
                    }
                }
            }

            logger.info(TAG, "Load root element finished, cost " + (System.currentTimeMillis() - startInit) + " ms.");

            if (Warehouse.groupsIndex.size() == 0) {
                logger.error(TAG, "No mapping files were found, check your configuration please!");
            }

            if (ARouter.debuggable()) {
                logger.debug(TAG, String.format(Locale.getDefault(), "LogisticsCenter has already been loaded, GroupIndex[%d], InterceptorIndex[%d], ProviderIndex[%d]", Warehouse.groupsIndex.size(), Warehouse.interceptorsIndex.size(), Warehouse.providersIndex.size()));
            }
        } catch (Exception e) {
            throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");
        }
    }

遍历对应的生成的文件,是在ClassUtils.getFileNameByPackageName中进行的,将生成的对应的文件类名保存在Set集合中,然后遍历该集合,判断是Root、Interceptor、Provider,做分别的缓存处理。

    /**
     * 通过指定包名,扫描包下面包含的所有的ClassName
     *
     * @param context     U know
     * @param packageName 包名
     * @return 所有class的集合
     */
    public static Set<String> getFileNameByPackageName(Context context, final String packageName) throws PackageManager.NameNotFoundException, IOException, InterruptedException {
        final Set<String> classNames = new HashSet<>();

        List<String> paths = getSourcePaths(context);
        final CountDownLatch parserCtl = new CountDownLatch(paths.size());

        // 这里使用双重循环,比较耗费性能。
        // 所以使用了arouter-gradle-plugin插件,使用字节码插桩的方式,节约性能
        for (final String path : paths) {
            DefaultPoolExecutor.getInstance().execute(new Runnable() {
                @Override
                public void run() {
                    DexFile dexfile = null;

                    try {
                        if (path.endsWith(EXTRACTED_SUFFIX)) {
                            //NOT use new DexFile(path), because it will throw "permission error in /data/dalvik-cache"
                            dexfile = DexFile.loadDex(path, path + ".tmp", 0);
                        } else {
                            dexfile = new DexFile(path);
                        }

                        Enumeration<String> dexEntries = dexfile.entries();
                        while (dexEntries.hasMoreElements()) {
                            String className = dexEntries.nextElement();
                            if (className.startsWith(packageName)) {
                                classNames.add(className);
                            }
                        }
                    } catch (Throwable ignore) {
                        Log.e("ARouter", "Scan map file in dex files made error.", ignore);
                    } finally {
                        if (null != dexfile) {
                            try {
                                dexfile.close();
                            } catch (Throwable ignore) {
                            }
                        }

                        parserCtl.countDown();
                    }
                }
            });
        }

        parserCtl.await();

        Log.d(Consts.TAG, "Filter " + classNames.size() + " classes by packageName <" + packageName + ">");
        return classNames;
    }

3.IProvider实现类寻找

IProvider接口实现对象的赋值,其实也是通过@Autowired注解,而要获取IProvider接口实现对象,则是通过

ARouter.getInstance().navigation(HelloService.class);

这里最终是执行到_ARouter的一个navigation方法

(1)_ARouter.navigation(Class<? extends T> service)
    protected <T> T navigation(Class<? extends T> service) {
        try {
            // 从Provider缓存中取出IProvider接口路径对应的RouteMeta
            // 然后再根据该RouteMeta对象创建Postcard
            Postcard postcard = LogisticsCenter.buildProvider(service.getName());

            // Compatible 1.0.5 compiler sdk.
            // Earlier versions did not use the fully qualified name to get the service
            if (null == postcard) {
                // No service, or this service in old version.
                postcard = LogisticsCenter.buildProvider(service.getSimpleName());
            }

            if (null == postcard) {
                return null;
            }

            // Set application to postcard.
            postcard.setContext(mContext);

            LogisticsCenter.completion(postcard);
            return (T) postcard.getProvider();
        } catch (NoRouteFoundException ex) {
            logger.warning(Consts.TAG, ex.getMessage());
            return null;
        }
    }

这里最终还是调用到了LogisticsCenter.completion方法,在该方法中,会向Postcard对象中传入对应的IProvider接口实现类对象的初始化,用于被@Autowired注解的对象的赋值,也可以直接获取到该IProvider接口实现类对象,进行使用。IProvider接口实现类对象不能在页面跳转的时候传递,但是可以通过common定义对应的接口,然后在对应的组件实现该接口,比如可以在common中定义HelloService,在personal组件实现HelloServiceImpl,HelloServiceImpl使用@Route注解,接着可以在比如news组件通过HelloService找到该HelloServiceImpl进行使用。

三、ARouter的初始化

在Application的onCreate中调用

        if (BuildConfig.DEBUG) {           // These two lines must be written before init, otherwise these configurations will be invalid in the init process
            ARouter.openLog();     // Print log
            ARouter.openDebug();   // Turn on debugging mode (If you are running in InstantRun mode, you must turn on debug mode! Online version needs to be closed, otherwise there is a security risk)
        }
        ARouter.init(this); // As early as possible, it is recommended to initialize in the Application

这里ARouter.init()就是初始化整个路由表的分组、拦截器分组、服务分组等,保存在Warehouse中的不同的静态Map集合中,并且使用分组名称作为对应的key。
这里其实就是全局保存了每个分组的Class
获取到ARouter注解处理器生成的对应的ClassName,然后反射创建Root文件类对象,接着调用loadInfo方法,将@Route路由值作为key,对应的对应的Group、Interceptor、Service分别保存在不同的静态Map集合中。

    public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
        mContext = context;
        executor = tpe;

        try {
            long startInit = System.currentTimeMillis();
            //billy.qi modified at 2017-12-06
            //load by plugin first
            loadRouterMap();
            if (registerByPlugin) {
                logger.info(TAG, "Load router map by arouter-auto-register plugin.");
            } else {
                Set<String> routerMap;

                // It will rebuild router map every times when debuggable.
                if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
                    logger.info(TAG, "Run with debug mode or new install, rebuild router map.");
                    // These class was generated by arouter-compiler.
                    // 取出对应的Root的className集合
                    routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
                    if (!routerMap.isEmpty()) {
                        context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();
                    }

                    PackageUtils.updateVersion(context);    // Save new version name when router map update finishes.
                } else {
                    logger.info(TAG, "Load router map from cache.");
                    routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
                }

                logger.info(TAG, "Find router map finished, map size = " + routerMap.size() + ", cost " + (System.currentTimeMillis() - startInit) + " ms.");
                startInit = System.currentTimeMillis();
                // 遍历Root文件的className集合,反射创建Root对象
                // 然后调用loadInfo方法将分组Group的Class保存在Warehouse中的Map集合
                for (String className : routerMap) {
                    if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
                        // This one of root elements, load root.
                        ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
                    } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
                        // Load interceptorMeta
                        ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
                    } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
                        // Load providerIndex
                        ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
                    }
                }
            }

            logger.info(TAG, "Load root element finished, cost " + (System.currentTimeMillis() - startInit) + " ms.");

            if (Warehouse.groupsIndex.size() == 0) {
                logger.error(TAG, "No mapping files were found, check your configuration please!");
            }

            if (ARouter.debuggable()) {
                logger.debug(TAG, String.format(Locale.getDefault(), "LogisticsCenter has already been loaded, GroupIndex[%d], InterceptorIndex[%d], ProviderIndex[%d]", Warehouse.groupsIndex.size(), Warehouse.interceptorsIndex.size(), Warehouse.providersIndex.size()));
            }
        } catch (Exception e) {
            throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");
        }
    }

而Group中的具体的RouteMeta则是在调用navigation()方法的时候,加入到Warehouse.routes集合中,RouteMeta中的信息一般是:具体的类的Class、path路径、group分组等
Class就是用来在startActivity的时候用的,如果是Service的话,就是用来反射创建对象。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容