文章目录
一、参数自动注入
二、自定义注解
三、使用 @Extra 自定义注解
四、注解处理器解析 @Extra 自定义注解 并生成相应 Activity 对应代码
五、博客资源
组件化系列博客 :
【Android 组件化】从模块化到组件化
【Android 组件化】使用 Gradle 实现组件化 ( Gradle 变量定义与使用 )
【Android 组件化】使用 Gradle 实现组件化 ( 组件模式与集成模式切换 )
【Android 组件化】使用 Gradle 实现组件化 ( 组件 / 集成模式下的 Library Module 开发 )
【Android 组件化】路由组件 ( 路由组件结构 )
【Android 组件化】路由组件 ( 注解处理器获取被注解的节点 )
【Android 组件化】路由组件 ( 注解处理器中使用 JavaPoet 生成代码 )
【Android 组件化】路由组件 ( 注解处理器参数选项设置 )
【Android 组件化】路由组件 ( 构造路由表中的路由信息 )
【Android 组件化】路由组件 ( 使用 JavaPoet 生成路由表类 )
【Android 组件化】路由组件 ( 组件间共享的服务 )
【Android 组件化】路由组件 ( 生成 Root 类记录模块中的路由表 )
【Android 组件化】路由组件 ( 运行时获取 注解处理器 生成的路由表 )
【Android 组件化】路由组件 ( 路由框架概述 )
【Android 组件化】路由组件 ( 页面跳转参数传递注解 )
一、参数自动注入
在 组件化 中 , 使用 路由组件 进行界面跳转时 , 涉及到参数的传递 , 传递过去的参数需要在目的地 Activity 的 onCreate 方法中 , 调用 getIntent().getXxxExtra() 获取到传递的值 ;
如果一次性传递 十几个 , 乃至几十个参数 , 这样就需要写很多次 getIntent().getXxxExtra() 样式的代码 , 这里引入注入框架 , 类似于 ButterKnife , 只要在目的 Activity 中的成员属性上标注注解 , 可以自动生成 getIntent().getXxxExtra() 相关逻辑 , 开发者不必手动编写此类逻辑 ;
ButterKnife 的作用是在 Activity 的成员属性上标注 @BindView 注解 , 自动生成 findViewById 代码 ;
二、自定义注解
自定义 Extra 注解 ,
@Target({ElementType.FIELD}) 元注解表示该注解用于标注成员字段 ,
@Retention(RetentionPolicy.CLASS) 元注解表示该注解保留到字节码编译时 ,
注解中定义了一个注解属性 name , 默认值为 “” ;
自定义注解代码示例 :
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; /** * 参数自动注入注解 * 该注解使用在 成员字段 上面 */ @Target({ElementType.FIELD}) @Retention(RetentionPolicy.CLASS) public @interface Extra { /** * 参数名称 * @return */ String name() default ""; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
三、使用 @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 { /** * 姓名 */ @Extra private String name; /** * 年龄 */ @Extra private int age; /** * 身高 */ @Extra private int height; /** * 体重 */ @Extra private int weight; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = findViewById(R.id.toolbar); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
四、注解处理器解析 @Extra 自定义注解 并生成相应 Activity 对应代码
注解处理器中解析上述注解 , 生成如下代码 , 生成代码位置 " D:
注解处理器中解析上述注解 , 生成如下代码 , 生成代码位置 " D:\002_Project\002_Android_Learn\Component\library3\build\generated\ap_generated_sources\debug\out\kim\hsl\library3\MainActivity_Extra.java "
2_Project
注解处理器中解析上述注解 , 生成如下代码 , 生成代码位置 " D:\002_Project\002_Android_Learn\Component\library3\build\generated\ap_generated_sources\debug\out\kim\hsl\library3\MainActivity_Extra.java "
2_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 { @Override public 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); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
生成上述代码的注解处理器 :
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; // 注解处理器接收的参数 @SupportedOptions("moduleName") // 自动注册注解处理器 @AutoService(Processor.class) // 支持的注解类型 @SupportedAnnotationTypes({"kim.hsl.router_annotation.Extra"}) // 支持的 Java 版本 @SupportedSourceVersion(SourceVersion.RELEASE_8) public class ExtraProcessor extends AbstractProcessor { /** * 注解处理器中使用 Messager 对象打印日志 */ private Messager mMessager; /** * 用于写出生成的 Java 代码 */ private Filer mFiler; /** * 注解节点工具 */ private Elements mElementUtils; /** * 类工具 */ private Types mTypeUtils; /** * 获取的 moduleName 参数 */ private String mModuleName; /** * 获取所有需要注入的节点集合 , 并按照其父节点 Activity 进行分组 * 键 ( Key ) : Activity 节点 * 值 ( Value ) : Activity 中被 @Extra 注解的属性节点 */ private Map> mActivity2Field = new HashMap<>(); /** * 该函数在初始化时调用 , 相当于构造函数 * @param processingEnvironment */ @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { super.init(processingEnvironment); // 获取打印日志接口 this.mMessager = processingEnvironment.getMessager(); // 测试日志打印 mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : Messager Print Log"); this.mFiler = processingEnvironment.getFiler(); this.mElementUtils = processingEnvironment.getElementUtils(); this.mTypeUtils = processingEnvironment.getTypeUtils(); // 获取 moduleName 参数 // 先获取 注解处理器 选项 Map options = processingEnvironment.getOptions(); if (options != null){ mModuleName = options.get("moduleName"); mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : 打印 moduleName 参数 : " + mModuleName); } } /** * 该函数在注解处理器注册时自动执行, 是处理注解的核心函数 * * Set extends TypeElement> set 参数 : 该集合表示使用了相关注解的节点的集合 * * @param set * @param roundEnvironment * @return */ @Override public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) { mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : " + mModuleName + " process "); if (set == null || set.isEmpty()){ // 如果没有检测到注解 , 直接退出 mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : 检测到注解为空 , 直接退出 mModuleName : " + mModuleName); return false; } // 获取被 @Extra 注解的属性节点集合 Set extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Extra.class); // 采集这些属性节点集合的 类型 和 变量名称 for (Element element : elements) { // 获取这些被 @Extra 标注的字段的父节点 Activity 节点 TypeElement activityElement = (TypeElement) element.getEnclosingElement(); if (mActivity2Field.containsKey(activityElement)) { // 如果该 Activity 父节点存在 , 直接添加到子节点集合中 mActivity2Field.get(activityElement).add(element); } else { // 如果该 Activity 父节点不存在 , 先创建子节点集合 , 再添加到集合中 List childs = new ArrayList<>(); childs.add(element); mActivity2Field.put(activityElement, childs); } mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : " + mModuleName + " 添加注解类型 : " + element.getSimpleName()); } // 至此 , 已经将所有 Activity 以及其下使用 @Extra 标注的属性都存放在了 // Map> mActivity2Field 集合中 /* 生成 Java 代码 */ // 获取 Activity 类型 TypeMirror activityTypeMirror = mElementUtils.getTypeElement("android.app.Activity").asType(); // 获取 IExtra 接口类型节点 TypeElement IExtra = mElementUtils.getTypeElement("kim.hsl.route_core.template.IExtra"); // 生成 IExtra 接口中 void loadExtra(Object target); 方法的 Object target 参数 ParameterSpec objectParamSpec = ParameterSpec.builder(TypeName.OBJECT, "target").build(); // 遍历所有需要注入的 类:属性 for (Map.Entry> entry : mActivity2Field.entrySet()) { // 每个 Map 键值对元素都要生成一个对应的 Java 类 // 获取 Activity 类 TypeElement rawClassElement = entry.getKey(); // 如果该类不是 Activity 子类 , 直接抛出异常 if (!mTypeUtils.isSubtype(rawClassElement.asType(), activityTypeMirror)) { throw new RuntimeException("ExtraProcessor Activity 类型错误"); } // 创建 void loadExtra(Object target) 方法 MethodSpec.Builder builder = MethodSpec.methodBuilder("loadExtra") .addAnnotation(Override.class) .addModifiers(Modifier.PUBLIC) .addParameter(objectParamSpec); // 生成类型转换代码 : MainActivity t = (MainActivity)target; // 获取 Activity 类名称 ClassName className = ClassName.get(rawClassElement); // 类型转换, 将 Activity 类转为指定的 Activity 子类类型 builder.addStatement("$T t = ($T)target", className, className); mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : 开始循环 Map 元素个数" + entry.getValue().size()); // 遍历被 @Extra 标注的属性字段 for (int i = 0; i < entry.getValue().size(); i++) { Element element = entry.getValue().get(i); buildStatement(element, builder); } mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : 结束循环 Map 元素个数" + entry.getValue().size()); // 生成 java 类名, 原来的 Activity 类名基础上添加 "_Extra" 后缀 String extraClassName = rawClassElement.getSimpleName() + "_Extra"; // 创建 Java 类 TypeSpec typeSpec = TypeSpec.classBuilder(extraClassName) .addSuperinterface(ClassName.get(IExtra)) // 实现 IExtra 接口 .addModifiers(PUBLIC) // .addMethod(builder.build()) // 设置函数 .build(); // 正式创建 // Java 文件 JavaFile javaFile = JavaFile.builder(className.packageName(), typeSpec).build(); // 写出生成的 java 代码 try { javaFile.writeTo(mFiler); } catch (IOException e) { e.printStackTrace(); } mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : 生成文件结束 : " + 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 获得text String fieldName = element.getSimpleName().toString(); //获得注解 name值 , 默认是传入的 name 注解属性值 String extraName = element.getAnnotation(Extra.class).name(); mMessager.printMessage(Diagnostic.Kind.NOTE, "ExtraProcessor : " + mModuleName + " 处理注解类型 : " + typeMirror.toString() + " , 字段名称 : " + fieldName + " , 注解属性值 : " + extraName); if (extraName == null || extraName.length() == 0) { // 如果 name 注解属性值为空 , 则取值 字段名称 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{ //数组类型 if (type == TypeKind.ARRAY.ordinal()) { addArrayStatement(statement, fieldName, extraName, typeMirror, element, builder); } else { // 对象类型 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, TypeMirror typeMirror, Element elementm , MethodSpec.Builder builder) { // 获取 Parcelable 类型 TypeMirror parcelableType = mElementUtils.getTypeElement("android.os.Parcelable").asType(); // 处理数组 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 数组 String defaultValue = "t." + fieldName; // object数组 componentType 获得 object类型 ArrayTypeName arrayTypeName = (ArrayTypeName) ClassName.get(typeMirror); TypeElement typeElement = mElementUtils.getTypeElement(arrayTypeName .componentType.toString()); // 如果不是 Parcelable 抛异常退出 if (!mTypeUtils.isSubtype(typeElement.asType(), parcelableType)) { throw new RuntimeException("不支持的 Extra 类型 : " + 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 类型 TypeMirror parcelableType = mElementUtils.getTypeElement("android.os.Parcelable").asType(); // 获取 IService 类型 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 { // List TypeName typeName = ClassName.get(typeMirror); //泛型 if (typeName instanceof ParameterizedTypeName) { //list 或 arraylist ClassName rawType = ((ParameterizedTypeName) typeName).rawType; //泛型类型 List 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 类型 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); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
五、博客资源
博客源码 :
GitHub : https://github.com/han1202012/Component
CSDN 下载 :
Android NAT
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。