ARouter源碼解析

ARouter是阿里巴巴出品,幫助 Android App 進行組件化改造的路由框架,我們項目也使用的是ARouter路由框架進行解耦;
我打算分三部分進行解析ARouter框架:
第一部分:代碼生成
第二部分:路由加載
第三部分:路由跳轉

第一部分:代碼生成

ARouter使用annotationProcessor配合JavaPoet進行代碼生成;annotationProcessor顧名思義是註解處理器的意思。它對源代碼文件進行檢測找出其中的Annotation,根據註解自動生成代碼。 Annotation處理器在處理Annotation時可以根據源文件中的Annotation生成額外的源文件和其它的文件,之後將編譯生成的源文件和原來的源文件一起生成class文件。由於annotationProcessor不屬於本篇範疇請點擊這裏查看詳細用法。


上圖爲ARouter annotationProcessor的代碼;

AutowiredProcessor

AutowiredProcessor類的作用是根據Autowired註解的字段和這個註解字段的外圍類來生成對應的類,生成的這個類命名方式爲ClassName+\$$ARouter$$Autowired,並且實現接口implements ISyringepublic void inject(Object target)方法。ARouter.getInstance().inject(this);底層就調用的是這個inject方法。
如果上面這段文字很難理解請看下面源碼解析一目瞭然:

註解類
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.CLASS)
public @interface Autowired {
    // Mark param's name or service name.
    //用來指定獲取數據的名字,如果不設置直接用字段的名字獲取數據
    String name() default "";
    // If required, app will be crash when value is null.
    // Primitive type wont be check!
    //true,如果被修飾的字段沒有獲取到數據會拋出異常
    boolean required() default false;
    // Description of the field
    //對這個字段進行解釋,可以生成javadoc
    String desc() default "No desc.";
}
文件處理的入口方法
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        if (CollectionUtils.isNotEmpty(set)) {
            try {
                logger.info(">>> Found autowired field, start... <<<");
                //根據註解處理源碼,生成Map<TypeElement, List<Element>>形式的map,
                // TypeElement爲Autowired字段修飾的外圍類,List<Element>爲這個外圍類中Autowired修飾的所有字段
              categories(roundEnvironment.getElementsAnnotatedWith(Autowired.class));
                //根據上個方法生成的結構來創建java類
                generateHelper();
            } catch (Exception e) {
                logger.error(e);
            }
            return true;
        }
        return false;
}
處理註解字段和外圍類的方法
private void categories(Set<? extends Element> elements) throws IllegalAccessException {
        if (CollectionUtils.isNotEmpty(elements)) {
            for (Element element : elements) {
                //獲取這個element的外圍類
                TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();

                if (element.getModifiers().contains(Modifier.PRIVATE)) {
                    throw new IllegalAccessException("The autowired fields CAN NOT BE 'private'!!! please check field ["
                            + element.getSimpleName() + "] in class [" + enclosingElement.getQualifiedName() + "]");
                }
                //判斷外圍類是否存在
                if (parentAndChild.containsKey(enclosingElement)) { // Has categries
                    //如果存在直接將Autowired註解修飾的字段添加到這個外圍類中
                    parentAndChild.get(enclosingElement).add(element);
                } else {
                    //如果外圍類不存在,創建
                    List<Element> childs = new ArrayList<>();
                    childs.add(element);
                    parentAndChild.put(enclosingElement, childs);
                }
            }
            logger.info("categories finished.");
        }
}
根據上面方法過濾出的結構創建文件的方法
private void generateHelper() throws IOException, IllegalAccessException {
        TypeElement type_ISyringe = elements.getTypeElement(ISYRINGE);
        TypeElement type_JsonService = elements.getTypeElement(JSON_SERVICE);
        TypeMirror iProvider = elements.getTypeElement(Consts.IPROVIDER).asType();
        TypeMirror activityTm = elements.getTypeElement(Consts.ACTIVITY).asType();
        TypeMirror fragmentTm = elements.getTypeElement(Consts.FRAGMENT).asType();
        TypeMirror fragmentTmV4 = elements.getTypeElement(Consts.FRAGMENT_V4).asType();
        // Build input param name.
        //方法參數爲  (Object target)
        ParameterSpec objectParamSpec = ParameterSpec.builder(TypeName.OBJECT, "target").build();
        if (MapUtils.isNotEmpty(parentAndChild)) {
            for (Map.Entry<TypeElement, List<Element>> entry : parentAndChild.entrySet()) {
                // Build method : 'inject'
                /**
                 * 創建的方法爲
                 * Override
                 * public void inject(Object target);
                 */
                MethodSpec.Builder injectMethodBuilder = MethodSpec.methodBuilder(METHOD_INJECT)
                        .addAnnotation(Override.class)
                        .addModifiers(PUBLIC)
                        .addParameter(objectParamSpec);
                //外圍類
                TypeElement parent = entry.getKey();
                //所有註解的字段
                List<Element> childs = entry.getValue();
                //獲取外圍類包名加類的名字,例如:com.arouter.demo.Test1Activity
                String qualifiedName = parent.getQualifiedName().toString();
                //獲取包名例如:com.arouter.demo
                String packageName = qualifiedName.substring(0, qualifiedName.lastIndexOf("."));
                //拼接生成類的名字Test1Activity$$ARouter$$Autowired
                String fileName = parent.getSimpleName() + NAME_OF_AUTOWIRED;
                logger.info(">>> Start process " + childs.size() + " field in " + parent.getSimpleName() + " ... <<<");
                //類的信息 javadoc  public class Test1Activity$$ARouter$$Autowired implements ISyringe
                TypeSpec.Builder helper = TypeSpec.classBuilder(fileName)
                        .addJavadoc(WARNING_TIPS)
                        .addSuperinterface(ClassName.get(type_ISyringe))
                        .addModifiers(PUBLIC);
                //創建字段   private SerializationService serializationService;
                FieldSpec jsonServiceField = FieldSpec.builder(TypeName.get(type_JsonService.asType()), "serializationService", Modifier.PRIVATE).build();
                helper.addField(jsonServiceField);
                /**
                 * 在方法體內創建賦值代碼
                 * serializationService = ARouter.getInstance().navigation(ARouter.class);
                 * Test1Activity substitute = (Test1Activity)target;
                 */
                injectMethodBuilder.addStatement("serializationService = $T.getInstance().navigation($T.class);", ARouterClass, ClassName.get(type_JsonService));
                injectMethodBuilder.addStatement("$T substitute = ($T)target", ClassName.get(parent), ClassName.get(parent));
                // Generate method body, start inject.
                for (Element element : childs) {
                    Autowired fieldConfig = element.getAnnotation(Autowired.class);
                    String fieldName = element.getSimpleName().toString();
                    if (types.isSubtype(element.asType(), iProvider)) {  // It's provider
                        //如果繼承IProvider
                        //判斷Autowired是否寫了name,如果寫了就取name值獲取數據,如果沒寫就用field字段本身的名字獲取數據
                        if ("".equals(fieldConfig.name())) {    // User has not set service path, then use byType.
                            // Getter
                            //substitute.fieldName = ARouter.getInstance().navigation(ARouter.class);
                            injectMethodBuilder.addStatement(
                                    "substitute." + fieldName + " = $T.getInstance().navigation($T.class)",
                                    ARouterClass,
                                    ClassName.get(element.asType())
                            );
                        } else {    // use byName
                            // Getter
                            //substitute.fieldName = ARouter.getInstance().navigation(ARouter.class);
                            injectMethodBuilder.addStatement(
                                    "substitute." + fieldName + " = ($T)$T.getInstance().build($S).navigation();",
                                    ClassName.get(element.asType()),
                                    ARouterClass,
                                    fieldConfig.name()
                            );
                        }
                        // Validater
                        //如果Autowired中的required返回true,那麼fieldName
                        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
                        String statment = "substitute." + fieldName + " = substitute.";
                        boolean isActivity = false;
                        if (types.isSubtype(parent.asType(), activityTm)) {  // Activity, then use getIntent()
                            isActivity = true;
                            statment += "getIntent().";
                        } else if (types.isSubtype(parent.asType(), fragmentTm) || types.isSubtype(parent.asType(), fragmentTmV4)) {   // Fragment, then use getArguments()
                            statment += "getArguments().";
                        } else {
                            throw new IllegalAccessException("The field [" + fieldName + "] need autowired from intent, its parent must be activity or fragment!");
                        }
                        /**
                         * 如上代碼判斷如果是activity就用getIntent()形式
                         * 如果是fragment就用getArguments()形式
                         * substitute.fieldName = substitute.getIntent().getStringExtra();  //如下1可以由多種形式,下面展示了兩種形式
                         * serializationService.json2Object(substitute.getIntent().getStringExtra($S), $T.class)";
                         * if (null != serializationService){  //如2
                         *    substitute.fieldName = serializationService.json2Object(substitute.getIntent().getStringExtra($S), $T.class)";
                         * }else{
                         *    ARouter.e("ARouter::",You want automatic inject the field 'fieldName' in class 'Test1Activity' , then you should implement 'SerializationService' to support object auto inject!\")"
                         * }
                         */
                        statment = buildStatement(statment, typeUtils.typeExchange(element), isActivity); //1
                        if (statment.startsWith("serializationService.")) {   // Not mortals
                            injectMethodBuilder.beginControlFlow("if (null != serializationService)");   //2
                            injectMethodBuilder.addStatement(
                                    "substitute." + fieldName + " = " + statment,
                                    (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 {
                            //substitute.fieldName = substitute.getIntent().getStringExtra();
                            injectMethodBuilder.addStatement(statment, StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name());
                        }

                        // Validator
                        //如果Autowired.required返回true,那麼對這個字段進行強制校驗,判斷爲null拋出異常
                        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. <<<");
        }
}
通過如下兩段代碼來看源文件和生成之後的文件

源文件

@Route(path = "/test/fragment")
public class BlankFragment extends Fragment {
    @Autowired
    String name;
    @Autowired(required = true)
    TestObj obj;
    public BlankFragment() {
        // Required empty public constructor
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        TextView textView = new TextView(getActivity());
        return textView;
    }
}

生成之後的文件

**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class BlankFragment$$ARouter$$Autowired implements ISyringe {
  private SerializationService serializationService;
  @Override
  public void inject(Object target) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);;
    BlankFragment substitute = (BlankFragment)target;
    substitute.name = substitute.getArguments().getString("name");
    if (null != serializationService) {
      substitute.obj = serializationService.json2Object(substitute.getArguments().getString("obj"), TestObj.class);
    } else {
      Log.e("ARouter::", "You want automatic inject the field 'obj' in class 'BlankFragment' , then you should implement 'SerializationService' to support object auto inject!");
    }
    if (null == substitute.obj) {
      Log.e("ARouter::", "The field 'obj' is null, in class '" + BlankFragment.class.getName() + "!");
    }
  }
}

InterceptorProcessor

InterceptorProcessor類的作用是根據Interceptor註解的類來生成對應的類,生成的這個類命名方式爲ARouter$$Interceptors$$moduleName其中moduleName爲build.gradle中配置的,並且實現接口implements IInterceptorGrouppublic void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors)方法。在ARouter初始化的時候通過這個類的這個方法來獲取所有的攔截器。

文件處理的入口方法
 @Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        if (CollectionUtils.isNotEmpty(annotations)) {
            //獲取所有被Interceptor註解的element
            Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Interceptor.class);
            try {
                //生成代碼
                parseInterceptors(elements);
            } catch (Exception e) {
                logger.error(e);
            }
            return true;
        }
        return false;
}
根據Interceptor註解生成代碼
private void parseInterceptors(Set<? extends Element> elements) throws IOException {
        if (CollectionUtils.isNotEmpty(elements)) {
            logger.info(">>> Found interceptors, size is " + elements.size() + " <<<");
            // Verify and cache, sort incidentally.
            for (Element element : elements) {
                //檢查攔截器,必須實現IInterceptor接口並且使用Interceptor註解
                if (verify(element)) {  // Check the interceptor meta
                    logger.info("A interceptor verify over, its " + element.asType());
                    Interceptor interceptor = element.getAnnotation(Interceptor.class);
                    Element lastInterceptor = interceptors.get(interceptor.priority());
                    //不允許多個攔截器使用同一個優先級
                    if (null != lastInterceptor) { // Added, throw exceptions
                        throw new IllegalArgumentException(
                                String.format(Locale.getDefault(), "More than one interceptors use same priority [%d], They are [%s] and [%s].",
                                        interceptor.priority(),
                                        lastInterceptor.getSimpleName(),
                                        element.getSimpleName())
                        );
                    }
                    //根據優先級緩存
                    interceptors.put(interceptor.priority(), element);
                } else {
                    logger.error("A interceptor verify failed, its " + element.asType());
                }
            }
            // Interface of ARouter.
            TypeElement type_ITollgate = elementUtil.getTypeElement(IINTERCEPTOR);
            TypeElement type_ITollgateGroup = elementUtil.getTypeElement(IINTERCEPTOR_GROUP);
            /**
             *  Build input type, format as :
             *
             *  ```Map<Integer, Class<? extends ITollgate>>```
             */
            ParameterizedTypeName inputMapTypeOfTollgate = ParameterizedTypeName.get(
                    ClassName.get(Map.class),
                    ClassName.get(Integer.class),
                    ParameterizedTypeName.get(
                            ClassName.get(Class.class),
                            WildcardTypeName.subtypeOf(ClassName.get(type_ITollgate))
                    )
            );
            // Build input param name.
            //方法參數  (Map<Integer, Class<? extends IInterceptor>> interceptors)
            ParameterSpec tollgateParamSpec = ParameterSpec.builder(inputMapTypeOfTollgate, "interceptors").build();
            // Build method : 'loadInto'
            /**
             * 創建方法
             * Override
             * public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors){}
             */
            MethodSpec.Builder loadIntoMethodOfTollgateBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
                    .addAnnotation(Override.class)
                    .addModifiers(PUBLIC)
                    .addParameter(tollgateParamSpec);
            // Generate
            /**
             * 根據緩存生成代碼
             * interceptors.put(priority,Test1Interceptor.class);
             */
            if (null != interceptors && interceptors.size() > 0) {
                // Build method body
                for (Map.Entry<Integer, Element> entry : interceptors.entrySet()) {
                    loadIntoMethodOfTollgateBuilder.addStatement("interceptors.put(" + entry.getKey() + ", $T.class)",
                            ClassName.get((TypeElement) entry.getValue()));
                }
            }
            // Write to disk(Write file even interceptors is empty.)
            /**
             * 生成類
             * moduleName爲每個module的build.gradle裏配置的
             * public class ARouter$$Interceptors$$moduleName implements IInterceptorGroup{
             *     public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceprors){
             *         interceptors.put(priority,Test1Interceptor.class);
             *     }
             * }
             */
            JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
                    TypeSpec.classBuilder(NAME_OF_INTERCEPTOR + SEPARATOR + moduleName)
                            .addModifiers(PUBLIC)
                            .addJavadoc(WARNING_TIPS)
                            .addMethod(loadIntoMethodOfTollgateBuilder.build())
                            .addSuperinterface(ClassName.get(type_ITollgateGroup))
                            .build()
            ).build().writeTo(mFiler);
            logger.info(">>> Interceptor group write over. <<<");
        }
}

源文件

@Interceptor(priority = 7)
public class Test1Interceptor implements IInterceptor {
    Context mContext;
    @Override
    public void process(final Postcard postcard, final InterceptorCallback callback) {

    }
    @Override
    public void init(Context context) {
    }
}

生成文件

public class ARouter$$Interceptors$$app implements IInterceptorGroup {
  @Override
  public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
    interceptors.put(7, Test1Interceptor.class);
  }
}

RouteProcessor

RouteProcessor類的作用是根據Route註解的類來生成對應的類,這個類是對應的路由表,也就是Group對應的path,path對應的類的Class。

文件處理的入口方法
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        if (CollectionUtils.isNotEmpty(annotations)) {
            //所有被Route註解的Element
            Set<? extends Element> routeElements = roundEnv.getElementsAnnotatedWith(Route.class);
            try {
                logger.info(">>> Found routes, start... <<<");
                //根據Element生成代碼
                this.parseRoutes(routeElements);
            } catch (Exception e) {
                logger.error(e);
            }
            return true;
        }
        return false;
}
根據Route生成代碼方法
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 :

               ```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.
              (Map<String, Class<? extends IRouteGroup>> routes)
             */
            ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot, "routes").build();
            //(Map<String, RouteMeta> atlas)
            ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "atlas").build();
            //(Map<String, RouteMeta> providers)
            ParameterSpec providerParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "providers").build();  // Ps. its param type same as groupParamSpec!
            /*
              Build method : 'loadInto'
              Override
              public void loadInto(Map<String, Class<? extends IRouteGroup>> routes);
             */
            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) {
                TypeMirror tm = element.asType();
                Route route = element.getAnnotation(Route.class);
                RouteMeta routeMete = null;
                //如下代碼組裝RouterMete路由元數據
                if (types.isSubtype(tm, type_Activity)) {   // 1               // Activity
                    logger.info(">>> Found activity route: " + tm.toString() + " <<<");

                    // 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.
                            //如果外圍類是Activity,裏面有被Autowired註解的字段且不是IProvider類型的,添加到Map中key爲名字,value爲字段類型的枚舉值,具體查看typeUtils.typeExchange(field)方法
                            Autowired paramConfig = field.getAnnotation(Autowired.class);
                            paramsType.put(StringUtils.isEmpty(paramConfig.name()) ?
                                    field.getSimpleName().toString() : paramConfig.name(), typeUtils.typeExchange(field));
                        }
                    }
                    routeMete = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType);
                } else if (types.isSubtype(tm, iProvider)) {         // IProvider
                    logger.info(">>> Found provider route: " + tm.toString() + " <<<");
                    routeMete = new RouteMeta(route, element, RouteType.PROVIDER, null);
                } else if (types.isSubtype(tm, type_Service)) {           // Service
                    logger.info(">>> Found service route: " + tm.toString() + " <<<");
                    routeMete = 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() + " <<<");
                    routeMete = new RouteMeta(route, element, RouteType.parse(FRAGMENT), null);
                }
                categories(routeMete);
                // if (StringUtils.isEmpty(moduleName)) {   // Hasn't generate the module name.
                //     moduleName = ModuleUtils.generateModuleName(element, logger);
                // }
            }
            /**
             * Override
             * public void loadInto(Map<String, RouteMeta> providers);
             */
            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();
                /**
                 * Override
                 * public void loadInto(Map<String, RouteMeta> atlas);
                 */
                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();
                            /**
                             * 如下代碼在方法public void loadInto(Map<String, RouteMeta> providers);中生成
                             * prvoiders.put("com.xxx.demo.HelloService",RouteMeta.build(RouteType.PROVIDER,HelloService.class,"/service/hello","service",null,priority,extra));
                             */
                            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
                                    //tm 和 iProvider 相同
                                    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
                                    // tm 是 iProvider 的子類
                                    loadIntoMethodOfProviderBuilder.addStatement(
                                            "providers.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, null, " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
                                            // tm.toString().substring(tm.toString().lastIndexOf(".") + 1),    // Spite unuseless name
                                            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
                    /**
                     * 如下代碼只有Activity的時候才運行,查看上面 1
                     * 生成代碼
                     * typeExchange,如上代碼,爲Autowired註解字段的類型
                     * put("Autowired.name",typeExchange);
                     */
                    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();
                    /**
                     * 如下代碼在方法public void loadInto(Map<String, RouteMeta> atlas);中生成如下
                     * atlas.put("/service/hello",RouteMeta.build(RouteType.PROVIDER,HelloService.class,"/service/hello","service",null,priority,extra));
                     * 如果routeMeta.getType()爲RouteType.ACTIVITY爲下面這種形式
                     * atlas.put("/service/hello",RouteMeta.build(RouteType.PROVIDER,HelloService.class,"/service/hello","service",new java.util.HashMap<String, Integer>(){{put("Autowired.name",typeExchange);},priority,extra));
                     */
                    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
                /**
                 * 如下代碼生成類
                 * package com.alibaba.android.arouter.routes;
                 * public class ARouter$$Group$$groupName implements IRouteGroup{
                 *     public void loadInto(Map<String, RouteMeta> atlas){
                 *          atlas.put("/service/hello",RouteMeta.build(RouteType.PROVIDER,HelloService.class,"/service/hello","service",null,priority,extra));
                 *          atlas.put("/service/hello",RouteMeta.build(RouteType.PROVIDER,HelloService.class,"/service/hello","service",new java.util.HashMap<String, Integer>(){{put("Autowired.name",typeExchange);},priority,extra));
                 *     }
                 * }
                 */
                String groupFileName = NAME_OF_GROUP + groupName;
                JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
                        TypeSpec.classBuilder(groupFileName)
                                .addJavadoc(WARNING_TIPS)
                                .addSuperinterface(ClassName.get(type_IRouteGroup))
                                .addModifiers(PUBLIC)
                                .addMethod(loadIntoMethodOfGroupBuilder.build())
                                .build()
                ).build().writeTo(mFiler);
                logger.info(">>> Generated group: " + groupName + "<<<");
                rootMap.put(groupName, groupFileName);
            }
            /**
             * 如下方法是在
             * Override public void loadInto(Map<String, Class<? extends IRouteGroup>> routes);
             * 方法中創建如下代碼
             * routes.put(groupName, ARouter$$Group$$groupName.class)
             */
            if (MapUtils.isNotEmpty(rootMap)) {
                // Generate root meta by group name, it must be generated before root, then I can findout 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
            /**
             * package com.alibaba.android.arouter.routes;
             * public class ARouter$$Providers$$moudleName implements IProviderGroup{
             *     public void loadInto(Map<String, RouteMeta> providers){
             *          prvoiders.put("com.xxx.demo.HelloService",RouteMeta.build(RouteType.PROVIDER,HelloService.class,"/service/hello","service",null,priority,extra));
             *     }
             * }
             */
            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.
            /**
             * package com.alibaba.android.arouter.routes;
             * public class ARouter&&Root$$moduleName implements IRouteRoot{
             *      Override
             *      public void loadInto(Map<String, Class<? extends IRouteGroup>> routes){
             *          routes.put(groupName, ARouter$$Group$$groupName.class)
             *      }
             * }
             */
            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 + " <<<");
        }
}

生成文件

public class ARouter$$Root$$app implements IRouteRoot {
  @Override
  public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
    routes.put("service", ARouter$$Group$$service.class);
    routes.put("test", ARouter$$Group$$test.class);
  }
}
public class ARouter$$Group$$service implements IRouteGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/service/hello", RouteMeta.build(RouteType.PROVIDER, HelloServiceImpl.class, "/service/hello", "service", null, -1, -2147483648));
    atlas.put("/service/json", RouteMeta.build(RouteType.PROVIDER, JsonServiceImpl.class, "/service/json", "service", null, -1, -2147483648));
    atlas.put("/service/single", RouteMeta.build(RouteType.PROVIDER, SingleService.class, "/service/single", "service", null, -1, -2147483648));
  }
}
總結:

上面對代碼生成部分做了詳細的代碼註釋,主要用到的技術就是annotationProcessor配合JavaPoet進行代碼生成。

第二部分:路由加載

本地生成文件也進行編譯打包,那麼程序是如何找到這些路由加載到內存中呢,我們直接找到'LogisticsCenter.public synchronized static void init(Context context, ThreadPoolExecutor tpe)'方法

public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
        mContext = context;
        executor = tpe;
        try {
            // These class was generate by arouter-compiler.
            //在所有的dex中根據package包名獲取arouter-compiler生成的class文件
            List<String> classFileNames = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);

            //根據上面代碼過濾出的class路徑來講Route加載到內存中
            for (String className : classFileNames) {
                if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
                    // This one of root elements, load root.
                    /**
                     * 獲取arouter-compiler生成的ARouter$$Root$$moduleName類中的映射表
                     * 例如
                     * public class ARouter$$Root$$app implements IRouteRoot {
                     *   @Override
                     *   public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
                     *     routes.put("service", ARouter$$Group$$service.class);
                     *     routes.put("test", ARouter$$Group$$test.class);
                     *   }
                     * }
                     */
                    ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
                } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
                    // Load interceptorMeta
                    /**
                     * 獲取arouter-compiler生成的ARouter$$Interceptors$$moduleName類的映射表
                     * 例如
                     * public class ARouter$$Interceptors$$app implements IInterceptorGroup {
                     *   @Override
                     *   public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
                     *     interceptors.put(7, Test1Interceptor.class);
                     *   }
                     * }
                     */
                    ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
                } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
                    // Load providerIndex
                    /**
                     * 獲取arouter-compiler生成的ARouter$$Providers$$moduleName類的映射表
                     * public class ARouter$$Providers$$app implements IProviderGroup {
                     *   @Override
                     *   public void loadInto(Map<String, RouteMeta> providers) {
                     *     providers.put("com.alibaba.android.arouter.demo.testservice.SingleService", RouteMeta.build(RouteType.PROVIDER, SingleService.class, "/service/single", "service", null, -1, -2147483648));
                     *   }
                     * }
                     */
                    ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
                }
            }
            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(mContext, ROUTE_ROOT_PAKCAGE);方法,這個方法又調用List<String> getSourcePaths(Context context)方法,如下兩個方法的代碼註釋:

/**
     * 通過指定包名,掃描包下面包含的所有的ClassName
     *
     * @param context     U know
     * @param packageName 包名
     * @return 所有class的集合
     */
    public static List<String> getFileNameByPackageName(Context context, String packageName) throws PackageManager.NameNotFoundException, IOException {
        List<String> classNames = new ArrayList<>();
        for (String path : getSourcePaths(context)) {
            DexFile dexfile = null;
            try {
                if (path.endsWith(EXTRACTED_SUFFIX)) {
                    //NOT use new DexFile(path), because it will throw "permission error in /data/dalvik-cache"
                    //提示權限錯誤 /data/dalvik-cache  這個目錄
                    dexfile = DexFile.loadDex(path, path + ".tmp", 0);
                } else {
                    //虛擬機將在目錄/data/dalvik-cache下生成對應的文件名字並打開它
                    dexfile = new DexFile(path);
                }
                Enumeration<String> dexEntries = dexfile.entries();
                while (dexEntries.hasMoreElements()) {
                    String className = dexEntries.nextElement();
                    if (className.contains(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) {
                    }
                }
            }
        }
        Log.d("ARouter", "Filter " + classNames.size() + " classes by packageName <" + packageName + ">");
        return classNames;
    }

List<String> getSourcePaths(Context context)方法

public static List<String> getSourcePaths(Context context) throws PackageManager.NameNotFoundException, IOException {
        ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0);
        File sourceApk = new File(applicationInfo.sourceDir);
//        Log.e(TAG,sourceApk.getAbsolutePath());
//        Log.e(TAG,"12121212 : " + applicationInfo.sourceDir);
        logger.info(TAG,"12121212 : " + applicationInfo.sourceDir);
        List<String> sourcePaths = new ArrayList<>();
        sourcePaths.add(applicationInfo.sourceDir); //add the default apk path
        //the prefix of extracted file, ie: test.classes
        String extractedFilePrefix = sourceApk.getName() + EXTRACTED_NAME_EXT;
        Log.e(TAG,extractedFilePrefix);
//        如果VM已經支持了MultiDex,就不要去Secondary Folder加載 Classesx.zip了,那裏已經麼有了
//        通過是否存在sp中的multidex.version是不準確的,因爲從低版本升級上來的用戶,是包含這個sp配置的
        /**
         * 如下這個方法判斷虛擬機是否支持multidex,java.vm.version大於2.1的就是art虛擬機默認支持multidex
         * 如果虛擬機爲art默認支持multidex那麼dex的路徑只有一個那就是applicationInfo.sourceDir例如: /data/app/com.alibaba.android.arouter.demo-wqT7WUHrcYy8UDBDFIXTmg==/base.apk
         * 如果虛擬機爲dalvik默認不支持multidex,且對dex進行分包處理那麼加載/data/data/com.alibaba.android.arouter.demo/code_cache/secondray-dexes/
         * 如果虛擬機爲dalvik默認不支持multidex,且由於代碼量太少沒有進行分包處理那麼加載applicationInfo.sourceDir路徑
         */
        if (!isVMMultidexCapable()) {
            //the total dex numbers
            int totalDexNumber = getMultiDexPreferences(context).getInt(KEY_DEX_NUMBER, 1);
            File dexDir = new File(applicationInfo.dataDir, SECONDARY_FOLDER_NAME);
            //掃描/data/data/com.alibaba.android.arouter.demo/code_cache/secondray-dexes/  路徑下所有的  xxx.apk.classes2.zip
            for (int secondaryNumber = 2; secondaryNumber <= totalDexNumber; secondaryNumber++) {
                //掃描/data/data/com.alibaba.android.arouter.demo/code_cache/secondray-dexes/ for each dex file, ie: test.classes2.zip, test.classes3.zip...
                String fileName = extractedFilePrefix + secondaryNumber + EXTRACTED_SUFFIX;
                File extractedFile = new File(dexDir, fileName);
                if (extractedFile.isFile()) {
                    sourcePaths.add(extractedFile.getAbsolutePath());
                    //we ignore the verify zip part
                } else {
                    throw new IOException("Missing extracted secondary dex file '" + extractedFile.getPath() + "'");
                }
            }
        }
        if (ARouter.debuggable()) { // Search instant run support only debuggable
            sourcePaths.addAll(tryLoadInstantRunDexFile(applicationInfo));
        }
        return sourcePaths;
}

經過'public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException'方法之後將arouter-compiler生成的代碼加載到內存中提供程序使用,如下類:

class Warehouse {
    // Cache route and metas
    //加載ARouter$$Root$$moduleName類的映射表
    static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
    static Map<String, RouteMeta> routes = new HashMap<>();
    // Cache provider
    static Map<Class, IProvider> providers = new HashMap<>();
    //加載ARouter$$Providers$$moduleName類的映射表
    static Map<String, RouteMeta> providersIndex = new HashMap<>();
    // Cache interceptor
    //加載ARouter$$Interceptors$$moduleName類的映射表
    static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
    static List<IInterceptor> interceptors = new ArrayList<>();
}

如下兩張圖片圖一爲art虛擬機編譯後獲取dex文件的目錄,圖二爲dalvik虛擬機編譯後獲取dex文件的目錄



總結:

根據虛擬機是否默認支持multidex,分別在不同的文件夾中掃描生成的zip或apk文件路徑;將路徑通過DexFile獲取所有的className,通過指定的package來過濾出有用的className;在將過濾出來的className填充到Warehouse類中的緩存中,給程序提供使用。

第一部分:路由跳轉

路由跳轉方法調用棧

//ARouter類
ARouter.getInstance().build(BaseConstantDef.ROUTER_PATH_AC1).navigation();
//_ARouter類
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback);
//如上方法中調用
LogisticsCenter.completion(postcard);//拼裝Postcard類
//符合要求執行攔截器
interceptorService.doInterceptions();
//最後調用真正的跳轉方法
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback)

上面是路由跳轉的方法調用棧,下面是代碼解析:
LogisticsCenter.completion(postcard)方法

public synchronized static void completion(Postcard postcard) {
        if (null == postcard) {
            throw new NoRouteFoundException(TAG + "No postcard!");
        }
        /**
         * 這部分代碼
         * 1. path在Warehouse.routes緩存中沒有,進入這個分支
         * 2. 根據group在Warehouse.groupsIndex中取出對應的IRouterGroup這個接口中存放的就是這個group中所有的path
         * 3. 取出之後將這個group下的所有path緩存到Warehouse.routes中,key爲path,value爲RouteMeta
         * 4. 緩存成功刪除Warehouse.groupsIndex中對應的group數據
         * 5. 重複調用completion方法,根據path命中緩存取出RouteMeta
         * 6. 根據RouteMeta來組裝Postcard
         * 7. 解析Uri中的參數,拼裝成Android的bundle傳輸
         * 8. routeMeta.getType()如果等於provider,那麼從Warehouse.providers中根據routeMeta.getDestination()取出Provider
         * 9. 如果取出爲空那麼創建,並且緩存到Warehouse.providers中,key爲provider的class,value爲provider的實例對象
         * 10. 如果是provider 設置postcard.greenChannel() 跳過攔截器
         * 11. 從第8點開始 routeMeta.getType()如果等於fragment,則直接設置postcard.greenChannel() 跳過攔截器
         */
        RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());   //  1
        if (null == routeMeta) {    // Maybe its does't exist, or didn't load.
            Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());  // 2 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 {
                    if (ARouter.debuggable()) {
                        logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] starts loading, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
                    }
                    IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();   // 3
                    iGroupInstance.loadInto(Warehouse.routes);
                    Warehouse.groupsIndex.remove(postcard.getGroup());  //  4
                    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() + "]");
                }
                completion(postcard);   // 5  Reload
            }
        } else {
            // 6
            postcard.setDestination(routeMeta.getDestination());
            postcard.setType(routeMeta.getType());
            postcard.setPriority(routeMeta.getPriority());
            postcard.setExtra(routeMeta.getExtra());
            //  7
            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 autoinject.
                    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:  // 8  if the route is provider, should find its instance
                    // Its provider, so it must be implememt 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 {
                            // 9
                            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();   // 10  Provider should skip all of interceptors
                    break;
                case FRAGMENT:
                    postcard.greenChannel();    // Fragment needn't interceptors
                default:
                    break;
            }
        }
}

interceptorService.doInterceptions()攔截器查看InterceptorServiceImpl源碼:

@Override
public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
        if (null != Warehouse.interceptors && Warehouse.interceptors.size() > 0) {
            checkInterceptorsInitStatus();
            if (!interceptorHasInit) {
                callback.onInterrupt(new HandlerException("Interceptors initialization takes too much time."));
                return;
            }
            LogisticsCenter.executor.execute(new Runnable() {
                @Override
                public void run() {
                    //這個同步工具類是爲了防止在攔截器中不回掉callback方法,或者攔截器中有線程延遲迴調callback方法
                    CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
                    try {
                        //遞歸執行所有攔截器
                        _excute(0, interceptorCounter, postcard);
                        //這段代碼是等待攔截器中線程執行完成回調callback來清除CountDownLatch標誌,但是他有個超時時間
                        interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);
                        if (interceptorCounter.getCount() > 0) {    // Cancel the navigation this time, if it hasn't return anythings.
                            callback.onInterrupt(new HandlerException("The interceptor processing timed out."));
                        } else if (null != postcard.getTag()) {    // Maybe some exception in the tag.
                            callback.onInterrupt(new HandlerException(postcard.getTag().toString()));
                        } else {
                            callback.onContinue(postcard);
                        }
                    } catch (Exception e) {
                        callback.onInterrupt(e);
                    }
                }
            });
        } else {
            callback.onContinue(postcard);
        }
}

protected Object 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) {
        try {
            //拼裝Postcard類
            LogisticsCenter.completion(postcard);
        } catch (NoRouteFoundException ex) {
            logger.warning(Consts.TAG, ex.getMessage());

            if (debuggable()) { // Show friendly tips for user.
                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.
            /**
             *除了provider和fragment都需要走攔截器,然後在發送navigation
             * 請查看InterceptorServiceImpl源碼異步執行所有攔截器,並且通過CountDownLatch來進行同步
             */
            interceptorService.doInterceptions(postcard, new InterceptorCallback() {
                /**
                 * Continue process
                 *
                 * @param postcard route meta
                 */
                @Override
                public void onContinue(Postcard postcard) {
                    //攔截器都正確返回
                    _navigation(context, 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(context, postcard, requestCode, callback);
        }
        return null;
}

參考文獻:
http://www.importnew.com/15731.html
https://it.baiked.com/jdkapi1.8/javax/lang/model/element/TypeElement.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章