官方文檔:
Android平臺頁面路由框架ARouterjava
阿里巴巴Arouter github地址以下:
ARouter gitHub 地址android
ARouter個人學習註釋GitHub地址:
ARoutergit
Arouter 使用Demo:
Android_Modularization_Demogithub
對AbstractProcessor不太熟悉的同窗,能夠參考:
Android中使用AbstractProcessor在編譯時生成代碼
基礎篇:帶你從頭至尾玩轉註解數組
該文章參考:
阿里路由框架--ARouter 源碼解析之Compiler
基礎篇:帶你從頭至尾玩轉註解app
arouter-compiler 經過AbstractProcessor在編譯時生成相關類文件框架
生成的文件位於如下目錄:
ide
上圖所示就是ARouter在編譯期間生成的類文件。函數
package com.alibaba.android.arouter.compiler.processor; /** * A processor used for find route. * * @author Alex <a href="mailto:zhilong.liu@aliyun.com">Contact me.</a> * @version 1.0 * @since 16/8/15 下午10:08 */ // 主要的做用是註解 processor 類,並對其生成 META-INF 的配置信息。 @AutoService(Processor.class) // ?????????????? // 這個註解用來註冊可能經過命令行傳遞給處理器的操做選項 @SupportedOptions(KEY_MODULE_NAME) // 標識該處理器支持的源碼版本 @SupportedSourceVersion(SourceVersion.RELEASE_7) // 這個 Processor 要處理的 Annotation 名字 // com.alibaba.android.arouter.facade.annotation.Route // com.alibaba.android.arouter.facade.annotation.Autowired @SupportedAnnotationTypes({ANNOTATION_TYPE_ROUTE, ANNOTATION_TYPE_AUTOWIRED}) public class RouteProcessor extends AbstractProcessor { // Filter用來建立新的源文件,class文件以及輔助文件 private Filer mFiler; // File util, write class file into disk. /** * 參考: * http://blog.csdn.net/dd864140130/article/details/53875814 * <p> * Elements 中包含用於操做Element的工具方法 * element表示一個靜態的,語言級別的構件。 * 而任何一個結構化文檔均可以看做是由不一樣的element組成的結構體,好比XML,JSON等。 * 對於java源文件來講,他一樣是一種結構化文檔: * package com.closedevice; //PackageElement * public class Main{ //TypeElement * private int x; //VariableElement * private Main(){ //ExecuteableElement * } * private void print(String msg){ //其中的參數部分String msg爲TypeElement * } * } */ private Elements elements; // Types中包含用於操做TypeMirror的工具方法 private Types types; // TypeMirror表明java語言中的類型. // Types包括基本類型,聲明類型(類類型和接口類型),數組,類型變量和空類型。也表明通配類型參數,可執行文件的簽名和返回類型等。 // TypeMirror類中最重要的是getKind()方法,該方法返回TypeKind類型,爲了方便你們理解 // Element表明源代碼,TypeElement表明的是源碼中的類型元素,好比類。 // 雖然咱們能夠從TypeElement中獲取類名,TypeElement中不包含類自己的信息, // 好比它的父類,要想獲取這信息須要藉助TypeMirror,能夠經過Element中的asType()獲取元素對應的TypeMirror private TypeMirror iProvider = null; // 判斷Element類型 private TypeUtils typeUtils; // // ModuleName and routeMeta. // 例: // group='test' // {type=FRAGMENT, // rawType=com.alibaba.android.arouter.demo.BlankFragment, // destination=null, // path='/test/fragment', // group='test', // priority=-1, // extra=-2147483648} private Map<String, Set<RouteMeta>> groupMap = new HashMap<>(); // 例: // group: test // group: ARouter$$Group$$test private Map<String, String> rootMap = new TreeMap<>(); // Map of root metas, used for generate class file in order. private String moduleName = null; // Module name, maybe its 'app' or others // 日誌封裝 // 經過Messager來報告錯誤,警告和其餘提示信息 private Logger logger; /** * Initializes the processor with the processing environment by * setting the {@code processingEnv} field to the value of the * {@code processingEnv} argument. An {@code * IllegalStateException} will be thrown if this method is called * more than once on the same object. * * @param processingEnv environment to access facilities the tool framework * provides to the processor * @throws IllegalStateException if this method is called more than once. */ @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); // Generate class. // Filter用來建立新的源文件,class文件以及輔助文件 mFiler = processingEnv.getFiler(); // Get class meta. // Elements 中包含用於操做Element的工具方法 elements = processingEnv.getElementUtils(); // Get type utils. types = processingEnv.getTypeUtils(); // 判斷Element類型 typeUtils = new TypeUtils(types, elements); // Messager用來報告錯誤,警告和其餘提示信息 logger = new Logger(processingEnv.getMessager()); // Package the log utils. // Attempt to get user configuration [moduleName] Map<String, String> options = processingEnv.getOptions(); logger.info("RouteProcessor options: " + options); if (MapUtils.isNotEmpty(options)) { moduleName = options.get(KEY_MODULE_NAME); } logger.info("RouteProcessor moduleName: " + moduleName); if (StringUtils.isNotEmpty(moduleName)) { moduleName = moduleName.replaceAll("[^0-9a-zA-Z_]+", ""); logger.info("The user has configuration the module name, it was [" + moduleName + "]"); } else { logger.error("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."); } iProvider = elements.getTypeElement(Consts.IPROVIDER).asType(); logger.info(">>> RouteProcessor init. <<<"); } /** * {@inheritDoc} * * @param annotations * @param roundEnv */ @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { logger.info("RouteProcessor process"); if (CollectionUtils.isNotEmpty(annotations)) { 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; } /** * @param routeElements * @throws IOException */ private void parseRoutes(Set<? extends Element> routeElements) throws IOException { logger.info("RouteProcessor parseRoutes"); if (CollectionUtils.isNotEmpty(routeElements)) { // Perpare the type an so on. logger.info(">>> Found routes, size is " + routeElements.size() + " <<<"); rootMap.clear(); // 獲取ACTIVITY, SERVICE, FRAGMENT, FRAGMENT_V4 這四種 類型鏡像 // android.app.Activity TypeMirror type_Activity = elements.getTypeElement(ACTIVITY).asType(); // android.app.Service TypeMirror type_Service = elements.getTypeElement(SERVICE).asType(); // android.app.Fragment TypeMirror fragmentTm = elements.getTypeElement(FRAGMENT).asType(); // android.support.v4.app.Fragment TypeMirror fragmentTmV4 = elements.getTypeElement(Consts.FRAGMENT_V4).asType(); // ARouter的接口 // Interface of ARouter // IRouteGroup TypeElement type_IRouteGroup = elements.getTypeElement(IROUTE_GROUP); // IProviderGroup TypeElement type_IProviderGroup = elements.getTypeElement(IPROVIDER_GROUP); // 下面就是遍歷獲取的註解信息,經過javapoet來生成類文件了 // RouteMeta ClassName routeMetaCn = ClassName.get(RouteMeta.class); // RouteType ClassName routeTypeCn = ClassName.get(RouteType.class); /** * * 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); * } * } * */ /** * ParameterizedTypeName用來建立類型對象,例以下面 * * 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)) ) ); /** * * public class ARouter$$Group$$test implements IRouteGroup { * @Override public void loadInto(Map<String, RouteMeta> atlas) { * atlas.put("/test/activity1", RouteMeta.build(RouteType.ACTIVITY, Test1Activity.class, "/test/activity1", "test", new java.util.HashMap<String, Integer>(){{put("pac", 9); put("ch", 5); put("fl", 6); put("obj", 10); put("name", 8); put("dou", 7); put("boy", 0); put("objList", 10); put("map", 10); put("age", 3); put("url", 8); put("height", 3); }}, -1, -2147483648)); * atlas.put("/test/activity2", RouteMeta.build(RouteType.ACTIVITY, Test2Activity.class, "/test/activity2", "test", new java.util.HashMap<String, Integer>(){{put("key1", 8); }}, -1, -2147483648)); * } * } * * */ /** * RouteMeta封裝了路由相關的信息 * *```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); logger.info("RouteProcessor routeElements.size() " + routeElements.size()); // 接下來的代碼就是遍歷註解元素,進行分組,進而生成java文件 // Follow a sequence, find out metas of group first, generate java file, then statistics them as root. for (Element element : routeElements) { logger.info("element " + element.getSimpleName()); // TypeMirror表明java語言中的類型 TypeMirror tm = element.asType(); // Route route = element.getAnnotation(Route.class); // RouteMeta routeMete = null; // 判斷類型 Activity 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()) { // 參數 自動裝填 // 1. 必須是field // 2. 必須有註解AutoWired // 3. 必須不是IProvider類型 if (field.getKind().isField() && field.getAnnotation(Autowired.class) != null && !types.isSubtype(field.asType(), iProvider)) { logger.info("Autowired field " + field.getSimpleName()); // 知足上述條件後,獲取註解 // It must be field, then it has annotation, but it not be provider. Autowired paramConfig = field.getAnnotation(Autowired.class); // Autowired支持寫別名,當指定name屬性以後,就會以name爲準,不然以field的名字爲準。 // TypeUtils是自定義工具類,用來判斷field的數據類型的,轉換成int值。 paramsType.put( StringUtils.isEmpty(paramConfig.name()) ? field.getSimpleName().toString() : paramConfig.name() , typeUtils.typeExchange(field)); } } logger.info("Autowired route.group " + route.group()); logger.info("Autowired route.name " + route.name()); logger.info("Autowired route.path " + route.path()); logger.info("Autowired route.extras " + route.extras()); logger.info("element " + element.getSimpleName()); logger.info("paramsType " + paramsType); /** * route: /test/activity1 * element: Test1Activity * ACTIVITY(0, "android.app.Activity") * paramsType 參數 參數對應類型int */ routeMete = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType); } // 若是是IProvider類型的註解,則直接建立一條PROVIDER類型的路由信息 else if (types.isSubtype(tm, iProvider)) { // IProvider logger.info(">>> Found provider route: " + tm.toString() + " <<<"); routeMete = new RouteMeta(route, element, RouteType.PROVIDER, null); } // 若是是Service類型的註解,則直接建立一條Service類型的路由信息 else if (types.isSubtype(tm, type_Service)) { // Service logger.info(">>> Found service route: " + tm.toString() + " <<<"); routeMete = new RouteMeta(route, element, RouteType.parse(SERVICE), null); } // 若是是fragmentTmV4類型的註解,則直接建立一條Fragment類型的路由信息 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); } else { throw new RuntimeException("ARouter::Compiler >>> Found unsupported class type, type = [" + types.toString() + "]."); } // 將路由信息進行分組,分組信息保存到 groupMap中 categories(routeMete); } /** * @Override * public void loadInto(Map<String, RouteMeta> providers) */ MethodSpec.Builder loadIntoMethodOfProviderBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO) .addAnnotation(Override.class) .addModifiers(PUBLIC) .addParameter(providerParamSpec); // 遍歷 groupMap // // 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); // 構建loadInto方法的方法體 // Build group method body Set<RouteMeta> groupData = entry.getValue(); // 循環 for (RouteMeta routeMeta : groupData) { // 類型 switch (routeMeta.getType()) { // PROVIDER(2, "com.alibaba.android.arouter.facade.template.IProvider") case PROVIDER:// Need cache provider's super class // List<? extends TypeMirror> interfaces = ((TypeElement) routeMeta.getRawType()).getInterfaces(); // 遍歷當前類的接口 for (TypeMirror tm : interfaces) { // 若是當前類直接實現了IProvider接口 if (types.isSameType(tm, iProvider)) { // Its implements iProvider interface himself. // This interface extend the IProvider, so it can be used for mark provider /** * @Route(path = "/service/single") * public class SingleService implements IProvider * * providers.put("com.alibaba.android.arouter.demo.testservice.SingleService", RouteMeta.build(RouteType.PROVIDER, SingleService.class, "/service/single", "service", null, -1, -2147483648)); */ 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()); } // 若是是接口繼承的IProvider else if (types.isSubtype(tm, iProvider)) { /** * @Route(path = "/service/hello") * public class HelloServiceImpl implements HelloService * public interface HelloService extends IProvider * // * providers.put("com.alibaba.android.arouter.demo.testservice.HelloService", RouteMeta.build(RouteType.PROVIDER, HelloServiceImpl.class, "/service/hello", "service", null, -1, -2147483648)); */ // 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; } // 形式如: put("pac", 9); put("obj", 10); // 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(); /** * atlas.put("/test/activity1", RouteMeta.build(RouteType.ACTIVITY, Test1Activity.class, "/test/activity1", "test", new java.util.HashMap<String, Integer>(){{put("pac", 9); put("ch", 5); put("fl", 6); put("obj", 10); put("name", 8); put("dou", 7); put("boy", 0); put("objList", 10); put("map", 10); put("age", 3); put("url", 8); put("height", 3); }}, -1, -2147483648)); */ 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 名稱 --"com.alibaba.android.arouter.routes" PACKAGE_OF_GENERATE_FILE, //java類名 TypeSpec.classBuilder(groupFileName) // doc .addJavadoc(WARNING_TIPS) // 添加繼承的接口 .addSuperinterface(ClassName.get(type_IRouteGroup)) // 做用域爲public .addModifiers(PUBLIC) // 添加函數(包括了函數裏面的代碼塊) .addMethod(loadIntoMethodOfGroupBuilder.build()) .build() ).build().writeTo(mFiler); logger.info("---rootMap---"); logger.info(">>> Generated group: " + groupName + "<<<"); logger.info(">>> Generated group: " + groupFileName + "<<<"); 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 + " <<<"); } } /** * Sort metas in group. * <p> * 將路由信息進行分組,分組信息保存到 groupMap中 * <p> * (每一個路由信息對象中都保存着它所屬的組別信息,在調用categories()函數以前全部的組別信息都是默認值"" ) * * @param routeMete metas. */ private void categories(RouteMeta routeMete) { logger.info("---categories---"); // 一、驗證路由信息的正確性 // 二、截取路徑字符串 獲取group if (routeVerify(routeMete)) { logger.info(">>> Start categories, group = " + routeMete.getGroup() + ", path = " + routeMete.getPath() + " <<<"); // 嘗試從groupMap中經過group名稱 獲取集合數據 Set<RouteMeta> routeMetas = groupMap.get(routeMete.getGroup()); // 集合數據爲空 if (CollectionUtils.isEmpty(routeMetas)) { // 建立組 Set<RouteMeta> routeMetaSet = new TreeSet<>(new Comparator<RouteMeta>() { @Override public int compare(RouteMeta r1, RouteMeta r2) { try { return r1.getPath().compareTo(r2.getPath()); } catch (NullPointerException npe) { logger.error(npe.getMessage()); return 0; } } }); // 添加到新建立的集合中 routeMetaSet.add(routeMete); // 集合添加到groupMap中 groupMap.put(routeMete.getGroup(), routeMetaSet); logger.info("routeMete: " + routeMete); logger.info("routeMete.getGroup(): " + routeMete.getGroup()); } else { // 添加到組中 routeMetas.add(routeMete); } } else { logger.warning(">>> Route meta verify error, group is " + routeMete.getGroup() + " <<<"); } } /** * 一、驗證路由信息的正確性 * 二、截取路徑字符串 獲取group * <p> * Verify the route meta * * @param meta raw meta */ private boolean routeVerify(RouteMeta meta) { String path = meta.getPath(); // 合法性判斷 if (StringUtils.isEmpty(path) || !path.startsWith("/")) { // The path must be start with '/' and not empty! return false; } // 沒有分組時,group爲"" if (StringUtils.isEmpty(meta.getGroup())) { // Use default group(the first word in path) try { // 截取路徑字符串 獲取group String defaultGroup = path.substring(1, path.indexOf("/", 1)); if (StringUtils.isEmpty(defaultGroup)) { return false; } meta.setGroup(defaultGroup); return true; } catch (Exception e) { logger.error("Failed to extract default group! " + e.getMessage()); return false; } } return true; } }