【Android 组件化】路由组件 ( 构造路由表中的路由信息 )
文章目錄
- 一、封裝路由信息
- 二、注解處理器 生成路由表信息
- 1、Activity 中使用 @Route 注解
- 2、注解處理器中判定注解是否檢測出來
- 3、獲取被 @Route 標(biāo)注的 注解節(jié)點(diǎn)
- 4、判斷被 @Route 標(biāo)注的 注解節(jié)點(diǎn)的類型
- 5、路由信息分組
- 三、完整的 注解處理器 代碼
- 四、博客資源
組件化系列博客 :
- 【Android 組件化】從模塊化到組件化
- 【Android 組件化】使用 Gradle 實(shí)現(xiàn)組件化 ( Gradle 變量定義與使用 )
- 【Android 組件化】使用 Gradle 實(shí)現(xiàn)組件化 ( 組件模式與集成模式切換 )
- 【Android 組件化】使用 Gradle 實(shí)現(xiàn)組件化 ( 組件 / 集成模式下的 Library Module 開發(fā) )
- 【Android 組件化】路由組件 ( 路由組件結(jié)構(gòu) )
- 【Android 組件化】路由組件 ( 注解處理器獲取被注解的節(jié)點(diǎn) )
- 【Android 組件化】路由組件 ( 注解處理器中使用 JavaPoet 生成代碼 )
- 【Android 組件化】路由組件 ( 注解處理器參數(shù)選項(xiàng)設(shè)置 )
在【Android 組件化】路由組件 ( 注解處理器參數(shù)選項(xiàng)設(shè)置 ) 博客中在注解處理器中 , 獲取了在 build.gradle 中設(shè)置的參數(shù) ;
本篇博客中講解 " 注解處理器 " 后續(xù)開發(fā) , 生成路由表中的 路由信息 ;
一、封裝路由信息
在 " 編譯時(shí)注解 " 依賴庫 Module 中 , 定義 封裝 路由信息 的 JavaBean 類 , 其中需要封裝以下數(shù)據(jù) ;
① 被 " kim.hsl.router_annotation.Route " 注解的 路由類型 , Activity 界面組件 / Service 服務(wù)組件 ;
② 被 " kim.hsl.router_annotation.Route " 注解的 " javax.lang.model.element.Element " 類型 注解節(jié)點(diǎn) ;
③ 被 " kim.hsl.router_annotation.Route " 注解的 Activity 界面組件 / Service 服務(wù)組件的 組件類對象 ;
④ 路由地址 , 字符串類型 ,
⑤ 路由分組 , 字符串類型 , 將路由信息根據(jù)路由分組拆分開進(jìn)行放置 ,
代碼示例 :
package kim.hsl.router_annotation.model;import javax.lang.model.element.Element; import kim.hsl.router_annotation.Route;/*** 存儲(chǔ)路由節(jié)點(diǎn)信息的 Bean*/ public class RouteBean {/*** 注解類的類型* Activity 界面 / Service 服務(wù)*/public enum Type {ACTIVITY,SERVICE}private Type type;/*** 被注解的節(jié)點(diǎn)*/private Element element;/*** 被注解類*/private Class<?> clazz;/*** 路由地址*/private String routeAddress;/*** 路由組*/private String routeGroup;public RouteBean(Type type, Element element, Route route) {this.type = type;this.element = element;this.clazz = null;this.routeAddress = route.path();this.routeGroup = route.group();}public RouteBean(Type type, Element element, Class<?> clazz, String routeAddress, String routeGroup) {this.type = type;this.element = element;this.clazz = clazz;this.routeAddress = routeAddress;this.routeGroup = routeGroup;}public Type getType() {return type;}public void setType(Type type) {this.type = type;}public Element getElement() {return element;}public void setElement(Element element) {this.element = element;}public Class<?> getClazz() {return clazz;}public void setClazz(Class<?> clazz) {this.clazz = clazz;}public String getRouteAddress() {return routeAddress;}public void setRouteAddress(String routeAddress) {this.routeAddress = routeAddress;}public String getRouteGroup() {return routeGroup;}public void setRouteGroup(String routeGroup) {this.routeGroup = routeGroup;} }二、注解處理器 生成路由表信息
1、Activity 中使用 @Route 注解
下面開始開發(fā) AbstractProcessor 注解處理器中的 process 方法 , 在該方法中生成 Java 代碼 ;
在 MainActivity 中使用了 @Route(path = “/app/MainActivity”) 標(biāo)注了 MainActivity 類 ;
@Route(path = "/app/MainActivity") public class MainActivity extends Activity { }2、注解處理器中判定注解是否檢測出來
在 注解處理器 中的 process 方法中 , 首先判定解析到了 注解節(jié)點(diǎn) , 如果沒有解析到注解節(jié)點(diǎn) , 就立刻退出 , 參考之前出現(xiàn)的問題 【錯(cuò)誤記錄】Android 編譯時(shí)技術(shù)報(bào)錯(cuò) ( 注解處理器 process 方法多次調(diào)用問題 ) ;
if (set == null || set.isEmpty()){// 如果沒有檢測到注解 , 直接退出return false; }3、獲取被 @Route 標(biāo)注的 注解節(jié)點(diǎn)
獲取被 Route 注解標(biāo)注的類節(jié)點(diǎn) , 調(diào)用 RoundEnvironment 參數(shù)的 getElementsAnnotatedWith 方法 , 傳入要獲取的注解類對象 ;
// 獲取被 @Route 注解的節(jié)點(diǎn) // 這些 注解節(jié)點(diǎn) 都是類節(jié)點(diǎn) , TypeElement 類型的 Set<? extends Element> routeElements = roundEnvironment.getElementsAnnotatedWith(Route.class);4、判斷被 @Route 標(biāo)注的 注解節(jié)點(diǎn)的類型
判斷被 @Route 標(biāo)注的 注解節(jié)點(diǎn)的類型 : 是否是 Activity 子類類型 ;
獲取 android.app.Activity 類型的 的 TypeElement 注解節(jié)點(diǎn) ;
// 獲取 android.app.Activity 類型的注解節(jié)點(diǎn) TypeElement activityElement = mElementUtils.getTypeElement("android.app.Activity");判定獲取的 Set<? extends Element> routeElements 節(jié)點(diǎn)是否是 " android.app.Activity " 子類節(jié)點(diǎn) , 如果是則創(chuàng)建路由信息對象 ;
mTypeUtils.isSubtype(element.asType(), activityElement.asType())創(chuàng)建路由信息對象 完整代碼示例 :
private void generateRouteClass(Set<? extends Element> routeElements) {// 獲取 android.app.Activity 類型的注解節(jié)點(diǎn)TypeElement activityElement = mElementUtils.getTypeElement("android.app.Activity");// 處理 @Route(path = "app/MainActivity") 節(jié)點(diǎn)for (Element element : routeElements) {// 獲取 Route 注解Route route = element.getAnnotation(Route.class);// 路由表中的單個(gè)路由對象RouteBean routeBean = null;// 打印類節(jié)點(diǎn)全類名mMessager.printMessage(Diagnostic.Kind.NOTE,"打印類節(jié)點(diǎn) typeElement : " + activityElement.getQualifiedName());// 判斷 typeMirror 注解節(jié)點(diǎn)是否是 Activity 類型if (mTypeUtils.isSubtype(element.asType(), activityElement.asType())) {// 該節(jié)點(diǎn)是 android.app.Activity 類型的routeBean = new RouteBean(RouteBean.Type.ACTIVITY, // 路由對象類型element, // 路由節(jié)點(diǎn)null, // 類對象route.path(), // 路由地址route.group()); // 路由組// 檢查路由地址checkRouteAddress(routeBean);// 打印路由信息mMessager.printMessage(Diagnostic.Kind.NOTE,"打印路由信息 : " + routeBean.toString());}else{// 該節(jié)點(diǎn)不是 android.app.Activity 類型的throw new RuntimeException("@Route 注解節(jié)點(diǎn)類型錯(cuò)誤");}}}5、路由信息分組
每個(gè)路由信息都有一個(gè)分組 , 在定義 Route 注解時(shí) , 分組為 “” 空字符串 ;
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.CLASS) public @interface Route {/*** 路由路徑, 標(biāo)識(shí)一個(gè)路由節(jié)點(diǎn)* 該字段沒有默認(rèn)值, 必須設(shè)置* @return*/String path();/*** 路由分組, 默認(rèn)為空, 選擇性設(shè)置* 路由節(jié)點(diǎn)可以按照分組進(jìn)行加載* @return*/String group() default ""; }根據(jù)設(shè)置的路由路徑 , @Route(path = “/app/MainActivity”) 中的 “/app/MainActivity” , 將其中的 app 作為路由分組 ;
截取路由地址 “/app/MainActivity” 中前兩個(gè)斜線之間字符串作為路由分組 ;
/*** 驗(yàn)證路由地址* @Route(path = "/app/MainActivity")* @param routeBean*/private void checkRouteAddress(RouteBean routeBean){// 獲取路由地址String routeAddress = routeBean.getRouteAddress();// 獲取路由分組String routeGroup = routeBean.getRouteGroup();// 驗(yàn)證路由地址是否以 "/" 開頭if (!routeAddress.startsWith("/")) {throw new RuntimeException("路由地址 " + routeAddress + " 格式錯(cuò)誤");}// 如果路由地址的分組為空 ,// 則截取第 0 和 第 1 個(gè) "/" 之間的字符串作為分組名稱if (routeGroup == null || "".equals(routeGroup)){String group = routeAddress.substring(routeAddress.indexOf("/", 0) + 1,routeAddress.indexOf("/", 1));if (group == null || "".equals(group)){throw new RuntimeException("路由地址 " + routeAddress + " 獲取分組錯(cuò)誤");}// 打印組名mMessager.printMessage(Diagnostic.Kind.NOTE,"打印路由地址 " + routeAddress + " 的組名為 " + group);// 正式設(shè)置路由地址分組routeBean.setRouteGroup(group);}}三、完整的 注解處理器 代碼
完整的 注解處理器 代碼 :
package kim.hsl.router_compiler;import com.google.auto.service.AutoService;import java.util.Map; import java.util.Set;import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Filer; import javax.annotation.processing.Messager; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedOptions; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import javax.tools.Diagnostic;import kim.hsl.router_annotation.Route; import kim.hsl.router_annotation.model.RouteBean;// 注解處理器接收的參數(shù) @SupportedOptions("moduleName") // 自動(dòng)注冊注解處理器 @AutoService(Processor.class) // 支持的注解類型 @SupportedAnnotationTypes({"kim.hsl.router_annotation.Route"}) // 支持的 Java 版本 @SupportedSourceVersion(SourceVersion.RELEASE_8) public class RouterProcessor extends AbstractProcessor {/*** 注解處理器中使用 Messager 對象打印日志*/private Messager mMessager;/*** 用于寫出生成的 Java 代碼*/private Filer mFiler;/*** 注解節(jié)點(diǎn)工具*/private Elements mElementUtils;/*** 類工具*/private Types mTypeUtils;/*** 獲取的 moduleName 參數(shù)*/private String mModuleName;/*** 該函數(shù)在初始化時(shí)調(diào)用 , 相當(dāng)于構(gòu)造函數(shù)* @param processingEnvironment*/@Overridepublic synchronized void init(ProcessingEnvironment processingEnvironment) {super.init(processingEnvironment);// 獲取打印日志接口this.mMessager = processingEnvironment.getMessager();// 測試日志打印mMessager.printMessage(Diagnostic.Kind.NOTE, "Messager Print Log");this.mFiler = processingEnvironment.getFiler();this.mElementUtils = processingEnvironment.getElementUtils();this.mTypeUtils = processingEnvironment.getTypeUtils();// 獲取 moduleName 參數(shù)// 先獲取 注解處理器 選項(xiàng)Map<String, String> options = processingEnvironment.getOptions();if (options != null){mModuleName = options.get("moduleName");mMessager.printMessage(Diagnostic.Kind.NOTE, "打印 moduleName 參數(shù) : " + mModuleName);}}/*** 該函數(shù)在注解處理器注冊時(shí)自動(dòng)執(zhí)行, 是處理注解的核心函數(shù)** Set<? extends TypeElement> set 參數(shù) : 該集合表示使用了相關(guān)注解的節(jié)點(diǎn)的集合** @param set* @param roundEnvironment* @return*/@Overridepublic boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {if (set == null || set.isEmpty()){// 如果沒有檢測到注解 , 直接退出return false;}// 獲取被 @Route 注解的節(jié)點(diǎn)// 這些 注解節(jié)點(diǎn) 都是類節(jié)點(diǎn) , TypeElement 類型的Set<? extends Element> routeElements = roundEnvironment.getElementsAnnotatedWith(Route.class);generateRouteClass(routeElements);return false;}private void generateRouteClass(Set<? extends Element> routeElements) {// 獲取 android.app.Activity 類型的注解節(jié)點(diǎn)TypeElement activityElement = mElementUtils.getTypeElement("android.app.Activity");// 處理 @Route(path = "app/MainActivity") 節(jié)點(diǎn)for (Element element : routeElements) {// 獲取 Route 注解Route route = element.getAnnotation(Route.class);// 路由表中的單個(gè)路由對象RouteBean routeBean = null;// 打印類節(jié)點(diǎn)全類名mMessager.printMessage(Diagnostic.Kind.NOTE,"打印類節(jié)點(diǎn) typeElement : " + activityElement.getQualifiedName());// 判斷 typeMirror 注解節(jié)點(diǎn)是否是 Activity 類型if (mTypeUtils.isSubtype(element.asType(), activityElement.asType())) {// 該節(jié)點(diǎn)是 android.app.Activity 類型的routeBean = new RouteBean(RouteBean.Type.ACTIVITY, // 路由對象類型element, // 路由節(jié)點(diǎn)null, // 類對象route.path(), // 路由地址route.group()); // 路由組// 檢查路由地址checkRouteAddress(routeBean);// 打印路由信息mMessager.printMessage(Diagnostic.Kind.NOTE,"打印路由信息 : " + routeBean.toString());}else{// 該節(jié)點(diǎn)不是 android.app.Activity 類型的throw new RuntimeException("@Route 注解節(jié)點(diǎn)類型錯(cuò)誤");}}}/*** 驗(yàn)證路由地址* @Route(path = "/app/MainActivity")* @param routeBean*/private void checkRouteAddress(RouteBean routeBean){// 獲取路由地址String routeAddress = routeBean.getRouteAddress();// 獲取路由分組String routeGroup = routeBean.getRouteGroup();// 驗(yàn)證路由地址是否以 "/" 開頭if (!routeAddress.startsWith("/")) {throw new RuntimeException("路由地址 " + routeAddress + " 格式錯(cuò)誤");}// 如果路由地址的分組為空 ,// 則截取第 0 和 第 1 個(gè) "/" 之間的字符串作為分組名稱if (routeGroup == null || "".equals(routeGroup)){String group = routeAddress.substring(routeAddress.indexOf("/", 0) + 1,routeAddress.indexOf("/", 1));if (group == null || "".equals(group)){throw new RuntimeException("路由地址 " + routeAddress + " 獲取分組錯(cuò)誤");}// 打印組名mMessager.printMessage(Diagnostic.Kind.NOTE,"打印路由地址 " + routeAddress + " 的組名為 " + group);// 正式設(shè)置路由地址分組routeBean.setRouteGroup(group);}} }執(zhí)行結(jié)果 :
注: Messager Print Log 注: 打印 moduleName 參數(shù) : app 注: 打印類節(jié)點(diǎn) typeElement : android.app.Activity 注: 打印路由地址 /app/MainActivity 的組名為 app 注: 打印路由信息 : RouteBean{type=ACTIVITY, element=kim.hsl.component.MainActivity, clazz=null, routeAddress='/app/MainActivity', routeGroup='app'}四、博客資源
博客源碼 :
- GitHub : https://github.com/han1202012/Component
- CSDN 下載 :
總結(jié)
以上是生活随笔為你收集整理的【Android 组件化】路由组件 ( 构造路由表中的路由信息 )的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 组件化】路由组件 (
- 下一篇: 【错误记录】Android Studio