美文网首页
阿里 ARouter 框架解析(二)

阿里 ARouter 框架解析(二)

作者: radish520like | 来源:发表于2018-05-28 15:33 被阅读0次

    前言

      ARouter 框架主要的三个模块


    image.png

      先来一张图


    image.png

    ARouter分析

    1.arouter-annotation

      我们看上图,主要 compiler 和 api,其实还有一层叫做 annotation,改层里面主要定义了一些元注解,比如我们使用的 @Router()就定义在这里。

    2.arouter-compiler

    image.png

      有三个 Processor 以及一些工具类,我们主要看 RouteProcessor,因为前面使用的 @Router 就是通过这个注解处理器来处理的。

    /**
     * 自动注册
     */
    @AutoService(Processor.class)
    /**
     * 处理接收的参数 代替 getSupportedOptions() 函数
     *     // Options of processor
     *     public static final String KEY_MODULE_NAME = "moduleName";
     *     接收什么参数?其实就是我们在 gradle 中配置的参数:
     *             javaCompileOptions {
     *                  annotationProcessorOptions {
     *                      arguments = [ moduleName : project.getName() ]
     *                  }
     *             }
     */
    @SupportedOptions(KEY_MODULE_NAME)
    /**
     * 指定使用 Java 的版本,代替 getSupportedSourceVersion() 函数
     */
    @SupportedSourceVersion(SourceVersion.RELEASE_7)
    /**
     * 指定可以处理哪些注解,代替 getSupportedAnnotationTypes() 函数
     *     private static final String FACADE_PACKAGE = "com.alibaba.android.arouter.facade";
     *     public static final String ANNOTATION_TYPE_ROUTE = FACADE_PACKAGE + ".annotation.Route";
     *     public static final String ANNOTATION_TYPE_AUTOWIRED = FACADE_PACKAGE + ".annotation.Autowired";
     *     所以其中 ANNOTATION_TYPE_ROUTE = "com.alibaba.android.arouter.facade.annotation.Route";
     */
    @SupportedAnnotationTypes({ANNOTATION_TYPE_ROUTE})
    public class RouteProcessor extends AbstractProcessor {
        /**
         * key 是 group 组,value 是 RouteMeta 集合
         */
        private Map<String, Set<RouteMeta>> groupMap = new HashMap<>(); // ModuleName and routeMeta.
        /**
         * key 是 group 组,value 是对应 Group 类对象名字
         */
        private Map<String, String> rootMap = new TreeMap<>();  // Map of root metas, used for generate class file in order.
        /**
         * 文件生成器 类/资源
         */
        private Filer mFiler;       // File util, write class file into disk.
        /**
         * apt 日志输出工具
         */
        private Logger logger;
        /**
         * type(类信息)工具类
         */
        private Types types;
        /**
         * 节点工具类(类、函数、属性都是节点)
         */
        private Elements elements;
        private TypeUtils typeUtils;
        private String moduleName = null;   // Module name, maybe its 'app' or others
        private TypeMirror iProvider = null;
    
        /**
         * 初始化方法,可以从 ProcessingEnvironment 中获取一些处理器工具
         */
        @Override
        public synchronized void init(ProcessingEnvironment processingEnv) {
            super.init(processingEnv);
    
            mFiler = processingEnv.getFiler();                // Generate class.
            types = processingEnv.getTypeUtils();             // Get type utils.
            elements = processingEnv.getElementUtils();       // Get class meta.
    
            typeUtils = new TypeUtils(types, elements);
            logger = new Logger(processingEnv.getMessager());   // Package the log utils.
    
            /**
             * 这里 options.key = moduleName
             *      options.value = app
             *      所以 moduleName = "app";
             */
            // Attempt to get user configuration [moduleName]
            Map<String, String> options = processingEnv.getOptions();
            if (MapUtils.isNotEmpty(options)) {
                moduleName = options.get(KEY_MODULE_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("These no module name, at 'build.gradle', like :\n" +
                        "apt {\n" +
                        "    arguments {\n" +
                        "        moduleName project.getName();\n" +
                        "    }\n" +
                        "}\n");
                throw new RuntimeException("ARouter::Compiler >>> No module name, for more information, look at gradle log.");
            }
    
            /**
             * 这里获取的是 com.alibaba.android.arouter.facade.template.IProvider 对象
             */
            iProvider = elements.getTypeElement(Consts.IPROVIDER).asType();
    
            logger.info(">>> RouteProcessor init. <<<");
        }
    
        /**
         * 注解处理器处理注解肯定会执行的方法
         *
         * @param annotations   使用了支持处理的注解的节点集合
         * @return true         表示后续处理器不会再处理,已经处理过了
         */
        @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)) {
                // Perpare the type an so on.
    
                logger.info(">>> Found routes, size is " + routeElements.size() + " <<<");
    
                rootMap.clear();
    
                /**
                 * 获取对应的节点信息
                 */
                TypeMirror type_Activity = elements.getTypeElement(ACTIVITY).asType();
                TypeMirror type_Service = elements.getTypeElement(SERVICE).asType();
                TypeMirror fragmentTm = elements.getTypeElement(FRAGMENT).asType();
                TypeMirror fragmentTmV4 = elements.getTypeElement(Consts.FRAGMENT_V4).asType();
    
                // Interface of ARouter
                TypeElement type_IRouteGroup = elements.getTypeElement(IROUTE_GROUP);
                TypeElement type_IProviderGroup = elements.getTypeElement(IPROVIDER_GROUP);
                ClassName routeMetaCn = ClassName.get(RouteMeta.class);
                ClassName routeTypeCn = ClassName.get(RouteType.class);
    
                /*
                   Build input type, format as :
                    使用 javapoet 生成如下代码
                   ```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)
                );
    
                /*
                    构造参数名
                  Build input param name.
                 */
                ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot, "routes").build();
                ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "atlas").build();
                ParameterSpec providerParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "providers").build();  // Ps. its param type same as groupParamSpec!
    
                /*
                    构造方法
                  Build method : 'loadInto'
                 */
                MethodSpec.Builder loadIntoMethodOfRootBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
                        .addAnnotation(Override.class)
                        .addModifiers(PUBLIC)
                        .addParameter(rootParamSpec);
    
                //  Follow a sequence, find out metas of group first, generate java file, then statistics them as root.
                for (Element element : routeElements) {
                    /**
                     * 这里 tm 获取的是被 @Router 注解了的节点的信息,比如:
                     *  com.alibaba.android.arouter.demo.testactivity.Test1Activity
                     */
                    TypeMirror tm = element.asType();
                    Route route = element.getAnnotation(Route.class);
                    RouteMeta routeMeta = null;
    
                    /**
                     * 判断注解是否在指定的类上使用,使用者可能将注解使用在错误的地方
                     */
                    if (types.isSubtype(tm, type_Activity)) {                 // Activity
                        logger.info(">>> Found activity route: " + tm.toString() + " <<<");
    
                        /**
                         * 下面是 @Autowired 注释的计息,我们先不看
                         */
                        // Get all fields annotation by @Autowired
                        Map<String, Integer> paramsType = new HashMap<>();
                        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);
                                paramsType.put(StringUtils.isEmpty(paramConfig.name()) ? field.getSimpleName().toString() : paramConfig.name(), typeUtils.typeExchange(field));
                            }
                        }
                        routeMeta = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType);
                    } else if (types.isSubtype(tm, 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
                        logger.info(">>> Found service route: " + tm.toString() + " <<<");
                        routeMeta = new RouteMeta(route, element, RouteType.parse(SERVICE), null);
                    } else if (types.isSubtype(tm, fragmentTm) || types.isSubtype(tm, fragmentTmV4)) {
                        logger.info(">>> Found fragment route: " + tm.toString() + " <<<");
                        routeMeta = new RouteMeta(route, element, RouteType.parse(FRAGMENT), null);
                    } else {
                        throw new RuntimeException("ARouter::Compiler >>> Found unsupported class type, type = [" + types.toString() + "].");
                    }
    
                    categories(routeMeta);
                    // if (StringUtils.isEmpty(moduleName)) {   // Hasn't generate the module name.
                    //     moduleName = ModuleUtils.generateModuleName(element, logger);
                    // }
                }
    
                /**
                 * 构建方法
                 */
                MethodSpec.Builder loadIntoMethodOfProviderBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
                        .addAnnotation(Override.class)
                        .addModifiers(PUBLIC)
                        .addParameter(providerParamSpec);
    
                // Start generate java source, structure is divided into upper and lower levels, used for demand initialization.
                for (Map.Entry<String, Set<RouteMeta>> entry : groupMap.entrySet()) {
                    String groupName = entry.getKey();
    
                    MethodSpec.Builder loadIntoMethodOfGroupBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
                            .addAnnotation(Override.class)
                            .addModifiers(PUBLIC)
                            .addParameter(groupParamSpec);
    
                    // Build group method body
                    /**
                     * 构建函数体中的内容
                     */
                    Set<RouteMeta> groupData = entry.getValue();
                    for (RouteMeta routeMeta : groupData) {
                        switch (routeMeta.getType()) {
                            case PROVIDER:  // Need cache provider's super class
                                List<? extends TypeMirror> interfaces = ((TypeElement) routeMeta.getRawType()).getInterfaces();
                                for (TypeMirror tm : interfaces) {
                                    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.get((TypeElement) routeMeta.getRawType()),
                                                routeMeta.getPath(),
                                                routeMeta.getGroup());
                                    } else if (types.isSubtype(tm, iProvider)) {
                                        // 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.get((TypeElement) routeMeta.getRawType()),
                                                routeMeta.getPath(),
                                                routeMeta.getGroup());
                                    }
                                }
                                break;
                            default:
                                break;
                        }
    
                        // Make map body for paramsType
                        StringBuilder mapBodyBuilder = new StringBuilder();
                        Map<String, Integer> paramsType = routeMeta.getParamsType();
                        if (MapUtils.isNotEmpty(paramsType)) {
                            for (Map.Entry<String, Integer> types : paramsType.entrySet()) {
                                mapBodyBuilder.append("put(\"").append(types.getKey()).append("\", ").append(types.getValue()).append("); ");
                            }
                        }
                        String mapBody = mapBodyBuilder.toString();
    
                        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.get((TypeElement) routeMeta.getRawType()),
                                routeMeta.getPath().toLowerCase(),
                                routeMeta.getGroup().toLowerCase());
                    }
    
                    // 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 + "<<<");
                    /**
                     * 例子:
                     * groupName = test
                     * groupFileName = ARouter$$Group$$test
                     */
                    rootMap.put(groupName, groupFileName);
                }
    
                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()));
                    }
                }
    
                // Wirte provider into disk
                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 + " <<<");
    
                // Write root meta into disk.
                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);
    
                logger.info(">>> Generated root, name is " + rootFileName + " <<<");
            }
        }
    
        /**
         * 配置 group
         * Sort metas in group.
         */
        private void categories(RouteMeta routeMete) {
            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;
                            }
                        }
                    });
                    //将存放了组,Route 等信息的 RouteMete 对象存放到 groupMap 集合中
                    routeMetaSet.add(routeMete);
                    groupMap.put(routeMete.getGroup(), routeMetaSet);
                } else {
                    routeMetas.add(routeMete);
                }
            } else {
                logger.warning(">>> Route meta verify error, group is " + routeMete.getGroup() + " <<<");
            }
        }
    
        /**
         * 验证合法性
         * 即验证 @Route(path = "/test/abc") 这个 path 的合法性
         */
        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;
            }
    
            /**
             * 这里,其实我们使用 Route 注解的时候还可以配置组
             *      @Route(path = "xxxxx" group="xxxx")
             *  如果group不写,默认是空字符串
             */
            if (StringUtils.isEmpty(meta.getGroup())) { // Use default group(the first word in path)
                try {
                    /**
                     * 这里如果 group 没有的话,我们就从 path 里面截取出组名,
                     * 这就是为什么我们path必须要写成 "/xxx/xxx"的格式
                     */
                    String defaultGroup = path.substring(1, path.indexOf("/", 1));
                    if (StringUtils.isEmpty(defaultGroup)) {
                        return false;
                    }
                    //将组信息存放到 RouteMeta 对象中
                    meta.setGroup(defaultGroup);
                    return true;
                } catch (Exception e) {
                    logger.error("Failed to extract default group! " + e.getMessage());
                    return false;
                }
            }
    
            return true;
        }
    }
    

      上面是 RouteProcessor 类的源代码,我把注释加上去了,可以自己仔细的看看。另外,如果想要了解 apt 和 javapoet 的可以去看另一篇文章。

    apt 和 javapoet : https://www.jianshu.com/p/15e9a67bd1dc

      现在如果我们,make app 后,可以看到如下文件。


    image.png

    3.arouter-api

      这部分代码,我们根据使用的情况来看源码,首先我们需要调用ARouter.init(getApplication());进行初始化。
      代码逐步跟踪到 LogisticsCenter 的 init() 方法。

     /**
         * LogisticsCenter init, load all metas in memory. Demand initialization
         */
        public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
            try {
                //billy.qi modified at 2017-12-06
                //load by plugin first
                loadRouterMap();
                //这里我修改了代码,让他直接走下面 else 中的代码
    //            if (registerByPlugin) {
                if (false) {
                } else {
                    Set<String> routerMap;
    //              这里 routerMap 这里面的值如下面图1
                    // These class was generated by arouter-compiler.
                    routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
    //              生成对应的对象并调用  loadInto() 方法,并且将Warehouse对应的字段传递进去,从而进行对其赋值
                    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);
                        }
                    }
                }
            } catch (Exception e) {
                throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");
            }
        }
    
    图1
      init 方法完成。
      界面跳转:ARouter.getInstance().build("/test/activity2").navigation();
    我们先看一下 build 方法的源码,这里说明一下,ARouter 对象的 init() 或者 build() 方法最终都会调用到 _ARouter 里面对应的方法中。
        public Postcard build(String path) {
            return _ARouter.getInstance().build(path);
        }
    
    
        protected Postcard build(String path) {
            if (TextUtils.isEmpty(path)) {
                throw new HandlerException(Consts.TAG + "Parameter is invalid!");
            } else {
                PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
                if (null != pService) {
                    path = pService.forString(path);
                }
                return build(path, extractGroup(path));
            }
        }
    

      这里我们点击应用内跳转后, 生成的 pService 会为 null,所以会走到 build(path,extractGroup(path));方法中。其中 extractGroup(path);方法其实就是从 path 中截取出 group 部分。

        protected Postcard build(String path, String group) {
            if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
                throw new HandlerException(Consts.TAG + "Parameter is invalid!");
            } else {
                PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
                if (null != pService) {
                    path = pService.forString(path);
                }
                //最终 new 出一个 Postcard() 并且保存了 path 和  group
                return new Postcard(path, group);
            }
        }
    

      build()方法玩了以后就是 navigation() 方法了。

        protected Object navigation(final Context context, final Postcard postcard, final int requestCode,
                                    final NavigationCallback callback) {
            try {
                LogisticsCenter.completion(postcard);
            } catch (NoRouteFoundException ex) {
                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.
                //...
            } else {
                return _navigation(context, postcard, requestCode, callback);
            }
            return null;
        }
    

      首先我们进入 LogisticsCenter.completion(postcard);方法。

    public synchronized static void completion(Postcard postcard) {
            if (null == postcard) {
                throw new NoRouteFoundException(TAG + "No postcard!");
            }
            /**
             * 先从仓库中查找 RouteMeta
             * static Map<String, RouteMeta> routes = new HashMap<>();
             * 其中 RouteMeta 里面存放的东西是 "/test/activity1" -> "RouteMeta 对象"
             * 并且 RouteMeta 对象包含了 /test/activity1 注解所对应的类对象
             */
            RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
            if (null == routeMeta) {    // Maybe its does't exist, or didn't load.
                /**
                 * 从 groupIndex 中获取
                 * static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
                 * 组表
                 */
    
                Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());  // Load route meta.
                if (null == groupMeta) {
                    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 {
                        //反射创建对象
                        IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
                        //调用 loadInto 方法,关于这两行代码,请看图2(映射文件)
                        iGroupInstance.loadInto(Warehouse.routes);
                        //从 groupsIndex 中移除(为了节省内存)
                        Warehouse.groupsIndex.remove(postcard.getGroup());
                    } catch (Exception e) {
                        throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
                    }
                    completion(postcard);   // Reload
                }
            } else {
                /*
                    将 routeMeta 中的信息复制到  postcard 信息中,因为 postcard 继承自 RouteMeta,
                    有些对应的字段在 RouteMeta 中
                 */
                postcard.setDestination(routeMeta.getDestination());
                postcard.setType(routeMeta.getType());
                postcard.setPriority(routeMeta.getPriority());
                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
                        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;
                }
            }
        }
    
    图2

      上述方法简单来说,就是将 postcard 对象中的信息进行了完善。回到 navigation 方法继续往下执行,在绿色通道上,不管我们是走 if 还是 else 都会调用到 _navigation() 方法。

        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:
                    // Build intent
                    final Intent intent = new Intent(currentContext, postcard.getDestination());
                    intent.putExtras(postcard.getExtras());
    
                    // Set flags.
                    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);
                    }
    
                    // Navigation in main looper.
                    new Handler(Looper.getMainLooper()).post(new Runnable() {
                        @Override
                        public void run() {
                            if (requestCode > 0) {  // Need start for result
                                ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());
                            } else {
                                ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());
                            }
    
                            if ((-1 != postcard.getEnterAnim() && -1 != postcard.getExitAnim()) && currentContext instanceof Activity) {    // Old version.
                                ((Activity) currentContext).overridePendingTransition(postcard.getEnterAnim(), postcard.getExitAnim());
                            }
    
                            if (null != callback) { // Navigation over.
                                callback.onArrival(postcard);
                            }
                        }
                    });
    
                    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;
        }
    

      这部分代码看起来就简单多了,其实就是实际的页面跳转了。

    相关文章

      网友评论

          本文标题:阿里 ARouter 框架解析(二)

          本文链接:https://www.haomeiwen.com/subject/jggsjftx.html