【Android 组件化】路由组件 ( 页面跳转参数依赖注入 )
文章目錄
- 一、參數(shù)自動(dòng)注入
- 二、自定義注解
- 三、使用 @Extra 自定義注解
- 四、注解處理器解析 @Extra 自定義注解 并生成相應(yīng) Activity 對(duì)應(yīng)代碼
- 五、博客資源
組件化系列博客 :
- 【Android 組件化】從模塊化到組件化
- 【Android 組件化】使用 Gradle 實(shí)現(xiàn)組件化 ( Gradle 變量定義與使用 )
- 【Android 組件化】使用 Gradle 實(shí)現(xiàn)組件化 ( 組件模式與集成模式切換 )
- 【Android 組件化】使用 Gradle 實(shí)現(xiàn)組件化 ( 組件 / 集成模式下的 Library Module 開(kāi)發(fā) )
- 【Android 組件化】路由組件 ( 路由組件結(jié)構(gòu) )
- 【Android 組件化】路由組件 ( 注解處理器獲取被注解的節(jié)點(diǎn) )
- 【Android 組件化】路由組件 ( 注解處理器中使用 JavaPoet 生成代碼 )
- 【Android 組件化】路由組件 ( 注解處理器參數(shù)選項(xiàng)設(shè)置 )
- 【Android 組件化】路由組件 ( 構(gòu)造路由表中的路由信息 )
- 【Android 組件化】路由組件 ( 使用 JavaPoet 生成路由表類(lèi) )
- 【Android 組件化】路由組件 ( 組件間共享的服務(wù) )
- 【Android 組件化】路由組件 ( 生成 Root 類(lèi)記錄模塊中的路由表 )
- 【Android 組件化】路由組件 ( 運(yùn)行時(shí)獲取 注解處理器 生成的路由表 )
- 【Android 組件化】路由組件 ( 路由框架概述 )
- 【Android 組件化】路由組件 ( 頁(yè)面跳轉(zhuǎn)參數(shù)傳遞注解 )
一、參數(shù)自動(dòng)注入
在 組件化 中 , 使用 路由組件 進(jìn)行界面跳轉(zhuǎn)時(shí) , 涉及到參數(shù)的傳遞 , 傳遞過(guò)去的參數(shù)需要在目的地 Activity 的 onCreate 方法中 , 調(diào)用 getIntent().getXxxExtra() 獲取到傳遞的值 ;
如果一次性傳遞 十幾個(gè) , 乃至幾十個(gè)參數(shù) , 這樣就需要寫(xiě)很多次 getIntent().getXxxExtra() 樣式的代碼 , 這里引入注入框架 , 類(lèi)似于 ButterKnife , 只要在目的 Activity 中的成員屬性上標(biāo)注注解 , 可以自動(dòng)生成 getIntent().getXxxExtra() 相關(guān)邏輯 , 開(kāi)發(fā)者不必手動(dòng)編寫(xiě)此類(lèi)邏輯 ;
ButterKnife 的作用是在 Activity 的成員屬性上標(biāo)注 @BindView 注解 , 自動(dòng)生成 findViewById 代碼 ;
二、自定義注解
自定義 Extra 注解 ,
@Target({ElementType.FIELD}) 元注解表示該注解用于標(biāo)注成員字段 ,
@Retention(RetentionPolicy.CLASS) 元注解表示該注解保留到字節(jié)碼編譯時(shí) ,
注解中定義了一個(gè)注解屬性 name , 默認(rèn)值為 “” ;
自定義注解代碼示例 :
package kim.hsl.router_annotation;import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/*** 參數(shù)自動(dòng)注入注解* 該注解使用在 成員字段 上面*/ @Target({ElementType.FIELD}) @Retention(RetentionPolicy.CLASS) public @interface Extra {/*** 參數(shù)名稱(chēng)* @return*/String name() default ""; }三、使用 @Extra 自定義注解
在 Activity 中 , 使用 @Route 和 @Extra 自定義注解 ;
package kim.hsl.library3;import android.os.Bundle;import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar;import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar;import android.view.View;import kim.hsl.router_annotation.Extra; import kim.hsl.router_annotation.Route;@Route(path = "/library3/MainActivity") public class MainActivity extends AppCompatActivity {/*** 姓名*/@Extraprivate String name;/*** 年齡*/@Extraprivate int age;/*** 身高*/@Extraprivate int height;/*** 體重*/@Extraprivate int weight;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Toolbar toolbar = findViewById(R.id.toolbar);} }四、注解處理器解析 @Extra 自定義注解 并生成相應(yīng) Activity 對(duì)應(yīng)代碼
注解處理器中解析上述注解 , 生成如下代碼 , 生成代碼位置 " D:\002_Project\002_Android_Learn\Component\library3\build\generated\ap_generated_sources\debug\out\kim\hsl\library3\MainActivity_Extra.java "
package kim.hsl.library3;import java.lang.Object; import java.lang.Override; import kim.hsl.route_core.template.IExtra;public class MainActivity_Extra implements IExtra {@Overridepublic void loadExtra(Object target) {MainActivity t = (MainActivity)target;t.name = t.getIntent().getStringExtra("name");t.age = t.getIntent().getIntExtra("age", t.age);t.height = t.getIntent().getIntExtra("height", t.height);t.weight = t.getIntent().getIntExtra("weight", t.weight);} }生成上述代碼的注解處理器 :
package kim.hsl.router_compiler;import com.google.auto.service.AutoService; import com.squareup.javapoet.ArrayTypeName; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.WildcardTypeName;import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap;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.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeKind; 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.Extra; import kim.hsl.router_annotation.Route; import kim.hsl.router_annotation.model.RouteBean;import static javax.lang.model.element.Modifier.PUBLIC;// 注解處理器接收的參數(shù) @SupportedOptions("moduleName") // 自動(dòng)注冊(cè)注解處理器 @AutoService(Processor.class) // 支持的注解類(lèi)型 @SupportedAnnotationTypes({"kim.hsl.router_annotation.Extra"}) // 支持的 Java 版本 @SupportedSourceVersion(SourceVersion.RELEASE_8) public class ExtraProcessor extends AbstractProcessor {/*** 注解處理器中使用 Messager 對(duì)象打印日志*/private Messager mMessager;/*** 用于寫(xiě)出生成的 Java 代碼*/private Filer mFiler;/*** 注解節(jié)點(diǎn)工具*/private Elements mElementUtils;/*** 類(lèi)工具*/private Types mTypeUtils;/*** 獲取的 moduleName 參數(shù)*/private String mModuleName;/*** 獲取所有需要注入的節(jié)點(diǎn)集合 , 并按照其父節(jié)點(diǎn) Activity 進(jìn)行分組* 鍵 ( Key ) : Activity 節(jié)點(diǎn)* 值 ( Value ) : Activity 中被 @Extra 注解的屬性節(jié)點(diǎn)*/private Map<TypeElement, List<Element>> mActivity2Field = new HashMap<>();/*** 該函數(shù)在初始化時(shí)調(diào)用 , 相當(dāng)于構(gòu)造函數(shù)* @param processingEnvironment*/@Overridepublic synchronized void init(ProcessingEnvironment processingEnvironment) {super.init(processingEnvironment);// 獲取打印日志接口this.mMessager = processingEnvironment.getMessager();// 測(cè)試日志打印mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : 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, "ExtraProcessor : 打印 moduleName 參數(shù) : " + mModuleName);}}/*** 該函數(shù)在注解處理器注冊(cè)時(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) {mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : " + mModuleName + " process ");if (set == null || set.isEmpty()){// 如果沒(méi)有檢測(cè)到注解 , 直接退出mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : 檢測(cè)到注解為空 , 直接退出 mModuleName : " + mModuleName);return false;}// 獲取被 @Extra 注解的屬性節(jié)點(diǎn)集合Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Extra.class);// 采集這些屬性節(jié)點(diǎn)集合的 類(lèi)型 和 變量名稱(chēng)for (Element element : elements) {// 獲取這些被 @Extra 標(biāo)注的字段的父節(jié)點(diǎn) Activity 節(jié)點(diǎn)TypeElement activityElement = (TypeElement) element.getEnclosingElement();if (mActivity2Field.containsKey(activityElement)) {// 如果該 Activity 父節(jié)點(diǎn)存在 , 直接添加到子節(jié)點(diǎn)集合中mActivity2Field.get(activityElement).add(element);} else {// 如果該 Activity 父節(jié)點(diǎn)不存在 , 先創(chuàng)建子節(jié)點(diǎn)集合 , 再添加到集合中List<Element> childs = new ArrayList<>();childs.add(element);mActivity2Field.put(activityElement, childs);}mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : " + mModuleName + " 添加注解類(lèi)型 : " + element.getSimpleName());}// 至此 , 已經(jīng)將所有 Activity 以及其下使用 @Extra 標(biāo)注的屬性都存放在了// Map<TypeElement, List<Element>> mActivity2Field 集合中/*生成 Java 代碼*/// 獲取 Activity 類(lèi)型TypeMirror activityTypeMirror = mElementUtils.getTypeElement("android.app.Activity").asType();// 獲取 IExtra 接口類(lèi)型節(jié)點(diǎn)TypeElement IExtra = mElementUtils.getTypeElement("kim.hsl.route_core.template.IExtra");// 生成 IExtra 接口中 void loadExtra(Object target); 方法的 Object target 參數(shù)ParameterSpec objectParamSpec = ParameterSpec.builder(TypeName.OBJECT, "target").build();// 遍歷所有需要注入的 類(lèi):屬性for (Map.Entry<TypeElement, List<Element>> entry : mActivity2Field.entrySet()) {// 每個(gè) Map 鍵值對(duì)元素都要生成一個(gè)對(duì)應(yīng)的 Java 類(lèi)// 獲取 Activity 類(lèi)TypeElement rawClassElement = entry.getKey();// 如果該類(lèi)不是 Activity 子類(lèi) , 直接拋出異常if (!mTypeUtils.isSubtype(rawClassElement.asType(), activityTypeMirror)) {throw new RuntimeException("ExtraProcessor Activity 類(lèi)型錯(cuò)誤");}// 創(chuàng)建 void loadExtra(Object target) 方法MethodSpec.Builder builder = MethodSpec.methodBuilder("loadExtra").addAnnotation(Override.class).addModifiers(Modifier.PUBLIC).addParameter(objectParamSpec);// 生成類(lèi)型轉(zhuǎn)換代碼 : MainActivity t = (MainActivity)target;// 獲取 Activity 類(lèi)名稱(chēng)ClassName className = ClassName.get(rawClassElement);// 類(lèi)型轉(zhuǎn)換, 將 Activity 類(lèi)轉(zhuǎn)為指定的 Activity 子類(lèi)類(lèi)型builder.addStatement("$T t = ($T)target", className, className);mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : 開(kāi)始循環(huán) Map 元素個(gè)數(shù)" + entry.getValue().size());// 遍歷被 @Extra 標(biāo)注的屬性字段for (int i = 0; i < entry.getValue().size(); i++) {Element element = entry.getValue().get(i);buildStatement(element, builder);}mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : 結(jié)束循環(huán) Map 元素個(gè)數(shù)" + entry.getValue().size());// 生成 java 類(lèi)名, 原來(lái)的 Activity 類(lèi)名基礎(chǔ)上添加 "_Extra" 后綴String extraClassName = rawClassElement.getSimpleName() + "_Extra";// 創(chuàng)建 Java 類(lèi)TypeSpec typeSpec = TypeSpec.classBuilder(extraClassName).addSuperinterface(ClassName.get(IExtra)) // 實(shí)現(xiàn) IExtra 接口.addModifiers(PUBLIC) //.addMethod(builder.build()) // 設(shè)置函數(shù).build(); // 正式創(chuàng)建// Java 文件JavaFile javaFile = JavaFile.builder(className.packageName(), typeSpec).build();// 寫(xiě)出生成的 java 代碼try {javaFile.writeTo(mFiler);} catch (IOException e) {e.printStackTrace();}mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : 生成文件結(jié)束 : " + mModuleName + " " +javaFile.toString());}return true;}/*** 拼裝如下代碼* t.a = t.getIntent().getStringExtra("a");* @param element*/public void buildStatement(Element element, MethodSpec.Builder builder) {TypeMirror typeMirror = element.asType();int type = typeMirror.getKind().ordinal();//屬性名 String text 獲得textString fieldName = element.getSimpleName().toString();//獲得注解 name值 , 默認(rèn)是傳入的 name 注解屬性值String extraName = element.getAnnotation(Extra.class).name();mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : " + mModuleName + " 處理注解類(lèi)型 : " + typeMirror.toString() + " , 字段名稱(chēng) : " + fieldName + " , 注解屬性值 : " + extraName);if (extraName == null || extraName.length() == 0) {// 如果 name 注解屬性值為空 , 則取值 字段名稱(chēng)extraName = fieldName;}mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : extraName : " + extraName);String defaultValue = "t." + fieldName;String statement = defaultValue + " = t.getIntent().";if (type == TypeKind.BOOLEAN.ordinal()) {statement += "getBooleanExtra($S, " + defaultValue + ")";} else if (type == TypeKind.BYTE.ordinal()) {statement += "getByteExtra($S, " + defaultValue + ")";} else if (type == TypeKind.SHORT.ordinal()) {statement += "getShortExtra($S, " + defaultValue + ")";} else if (type == TypeKind.INT.ordinal()) {statement += "getIntExtra($S, " + defaultValue + ")";} else if (type == TypeKind.LONG.ordinal()) {statement += "getLongExtra($S, " + defaultValue + ")";} else if (type == TypeKind.CHAR.ordinal()) {statement += "getCharExtra($S, " + defaultValue + ")";} else if (type == TypeKind.FLOAT.ordinal()) {statement += "getFloatExtra($S, " + defaultValue + ")";} else if (type == TypeKind.DOUBLE.ordinal()) {statement += "getDoubleExtra($S, " + defaultValue + ")";} else{//數(shù)組類(lèi)型if (type == TypeKind.ARRAY.ordinal()) {addArrayStatement(statement, fieldName, extraName, typeMirror, element, builder);} else {// 對(duì)象類(lèi)型addObjectStatement(statement, fieldName, extraName, typeMirror, element, builder);}return;}builder.addStatement(statement, extraName);mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : extraName : " + extraName + " 生成完畢");}private void addArrayStatement(String statement, String fieldName, String extraName, TypeMirrortypeMirror, Element elementm , MethodSpec.Builder builder) {// 獲取 Parcelable 類(lèi)型TypeMirror parcelableType = mElementUtils.getTypeElement("android.os.Parcelable").asType();// 處理數(shù)組switch (typeMirror.toString()) {case "boolean[]":statement += "getBooleanArrayExtra($S)";break;case "int[]":statement += "getIntArrayExtra($S)";break;case "short[]":statement += "getShortArrayExtra($S)";break;case "float[]":statement += "getFloatArrayExtra($S)";break;case "double[]":statement += "getDoubleArrayExtra($S)";break;case "byte[]":statement += "getByteArrayExtra($S)";break;case "char[]":statement += "getCharArrayExtra($S)";break;case "long[]":statement += "getLongArrayExtra($S)";break;case "java.lang.String[]":statement += "getStringArrayExtra($S)";break;default:// 處理 Parcelable 數(shù)組String defaultValue = "t." + fieldName;// object數(shù)組 componentType 獲得 object類(lèi)型ArrayTypeName arrayTypeName = (ArrayTypeName) ClassName.get(typeMirror);TypeElement typeElement = mElementUtils.getTypeElement(arrayTypeName.componentType.toString());// 如果不是 Parcelable 拋異常退出if (!mTypeUtils.isSubtype(typeElement.asType(), parcelableType)) {throw new RuntimeException("不支持的 Extra 類(lèi)型 : " + typeMirror);}// 字符串格式statement = "$T[] " + fieldName + " = t.getIntent()" + ".getParcelableArrayExtra" + "($S)";builder.addStatement(statement, parcelableType, extraName);builder.beginControlFlow("if( null != $L)", fieldName);statement = defaultValue + " = new $T[" + fieldName + ".length]";builder.addStatement(statement, arrayTypeName.componentType).beginControlFlow("for (int i = 0; i < " + fieldName + "" +".length; " +"i++)").addStatement(defaultValue + "[i] = ($T)" + fieldName + "[i]",arrayTypeName.componentType).endControlFlow();builder.endControlFlow();return;}builder.addStatement(statement, extraName);}private void addObjectStatement(String statement, String fieldName, String extraName,TypeMirror typeMirror,Element element, MethodSpec.Builder builder) {// 獲取 Parcelable 類(lèi)型TypeMirror parcelableType = mElementUtils.getTypeElement("android.os.Parcelable").asType();// 獲取 IService 類(lèi)型TypeMirror iServiceType = mElementUtils.getTypeElement("kim.hsl.route_core.template.IService").asType();if (mTypeUtils.isSubtype(typeMirror, parcelableType)) {statement += "getParcelableExtra($S)";} else if (typeMirror.toString().equals("java.lang.String")) {statement += "getStringExtra($S)";} else if (mTypeUtils.isSubtype(typeMirror, iServiceType)) {ClassName routerClassName = ClassName.get("kim.hsl.route_core", "Router");statement = "t." + fieldName + " = ($T) $T.getInstance().build($S).navigation()";builder.addStatement(statement, TypeName.get(element.asType()), routerClassName,extraName);return;} else {// ListTypeName typeName = ClassName.get(typeMirror);//泛型if (typeName instanceof ParameterizedTypeName) {//list 或 arraylistClassName rawType = ((ParameterizedTypeName) typeName).rawType;//泛型類(lèi)型List<TypeName> typeArguments = ((ParameterizedTypeName) typeName).typeArguments;if (!rawType.toString().equals("java.util.ArrayList") && !rawType.toString().equals("java.util.List")) {throw new RuntimeException("Not Support Inject Type:" + typeMirror + " " +element);}if (typeArguments.isEmpty() || typeArguments.size() != 1) {throw new RuntimeException("List Must Specify Generic Type:" + typeArguments);}TypeName typeArgumentName = typeArguments.get(0);TypeElement typeElement = mElementUtils.getTypeElement(typeArgumentName.toString());// Parcelable 類(lèi)型if (mTypeUtils.isSubtype(typeElement.asType(), parcelableType)) {statement += "getParcelableArrayListExtra($S)";} else if (typeElement.asType().toString().equals("java.lang.String")) {statement += "getStringArrayListExtra($S)";} else if (typeElement.asType().toString().equals("java.lang.Integer")) {statement += "getIntegerArrayListExtra($S)";} else {throw new RuntimeException("Not Support Generic Type : " + typeMirror + " " +element);}} else {throw new RuntimeException("Not Support Extra Type : " + typeMirror + " " +element);}}builder.addStatement(statement, extraName);}}五、博客資源
博客源碼 :
- GitHub : https://github.com/han1202012/Component
- CSDN 下載 :
總結(jié)
以上是生活随笔為你收集整理的【Android 组件化】路由组件 ( 页面跳转参数依赖注入 )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【Android 组件化】路由组件 (
- 下一篇: 【C 语言】文件操作 ( 写文本文件 |