0%

自定义注解,打造自己的框架 (中篇)

该系列介绍自定义注解,完成如下功能。

  • @BindView 代替 findViewById
  • @ClickResponder 代替 setOnClickListener
  • @LongClickResponder 代替 setOnLongClickListener
  • @IntentValue 代替 getIntent().getXXX
  • @UriValue 代替 getQueryParameter
  • @BroadcastResponder 代替 registerReceiver
  • @RouterModule、@RouterPath 来进行反依赖传递调用
    该系列源码在https://github.com/huangyuanlove/AndroidAnnotation
    使用编译时注解,生成辅助类来完成这些操作,尽量少的使用的反射功能。

本章先介绍 javapoet 和一丢丢反射相关的东西

javapoet

用来辅助生成java代码的库,可以看这里,有特别详细的示例。大致过了一遍,如下所示

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
public class TestJavaPoet {
public static void main(String[] args) {
TypeSpec clazz = clazz(builtinTypeField(), // int
arrayTypeField(), // int[]
refTypeField(), // File
typeField(), // T
parameterizedTypeField(), // List<String>
wildcardTypeField(), // List<? extends String>
constructor(), // 构造函数
method(code())); // 普通方法
JavaFile javaFile = JavaFile.builder("com.huangyuanlove.view_inject_compiler.test", clazz).build();

System.out.println(javaFile.toString());
}

/**
* `public abstract class Clazz<T> extends String implements Serializable, Comparable<String>, Comparable<? extends String> {
* ...
*/
private static TypeSpec clazz(FieldSpec builtinTypeField, FieldSpec arrayTypeField, FieldSpec refTypeField,
FieldSpec typeField, FieldSpec parameterizedTypeField, FieldSpec wildcardTypeField,
MethodSpec constructor, MethodSpec methodSpec) {
return TypeSpec.classBuilder("Clazz")
// 限定符
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
// 泛型
.addTypeVariable(TypeVariableName.get("T"))

// 继承与接口
.superclass(String.class)
.addSuperinterface(Serializable.class)
.addSuperinterface(ParameterizedTypeName.get(Comparable.class, String.class))
.addSuperinterface(ParameterizedTypeName.get(ClassName.get(Map.class),
TypeVariableName.get("T"),
WildcardTypeName.subtypeOf(String.class)))

// 初始化块
.addStaticBlock(CodeBlock.builder().build())
.addInitializerBlock(CodeBlock.builder().build())

// 属性
.addField(builtinTypeField)
.addField(arrayTypeField)
.addField(refTypeField)
.addField(typeField)
.addField(parameterizedTypeField)
.addField(wildcardTypeField)

// 方法 (构造函数也在此定义)
.addMethod(constructor)
.addMethod(methodSpec)

// 内部类
.addType(TypeSpec.classBuilder("InnerClass").build())

.build();
}

/**
* 内置类型
*/
private static FieldSpec builtinTypeField() {
// private int mInt;
return FieldSpec.builder(int.class, "mInt", Modifier.PRIVATE).build();
}

/**
* 数组类型
*/
private static FieldSpec arrayTypeField() {
// private int[] mArr;
return FieldSpec.builder(int[].class, "mArr", Modifier.PRIVATE).build();
}

/**
* 需要导入 import 的类型
*/
private static FieldSpec refTypeField() {
// private File mRef;
return FieldSpec.builder(File.class, "mRef", Modifier.PRIVATE).build();
}

/**
* 泛型
*/
private static FieldSpec typeField() {
// private File mT;
return FieldSpec.builder(TypeVariableName.get("T"), "mT", Modifier.PRIVATE).build();
}

/**
* 参数化类型
*/
private static FieldSpec parameterizedTypeField() {
// private List<String> mParameterizedField;
return FieldSpec.builder(ParameterizedTypeName.get(List.class, String.class),
"mParameterizedField",
Modifier.PRIVATE)
.build();
}

/**
* 通配符参数化类型
*/
private static FieldSpec wildcardTypeField() {
// private List<? extends String> mWildcardField;
return FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(List.class),
WildcardTypeName.subtypeOf(String.class)),
"mWildcardField",
Modifier.PRIVATE)
.build();
}

/**
* 构造函数
*/
private static MethodSpec constructor() {
return MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC)
.build();
}

/**
* `@Override
* public <T> Integer method(String string, T t, Map<Integer, ? extends T> map) throws IOException, RuntimeException {
* ...
* }`
*
*/
private static MethodSpec method(CodeBlock codeBlock) {
return MethodSpec.methodBuilder("method")
.addAnnotation(Override.class)
.addTypeVariable(TypeVariableName.get("T"))
.addModifiers(Modifier.PUBLIC)
.returns(int.class)
.addParameter(String.class, "string")
.addParameter(TypeVariableName.get("T"), "t")
.addParameter(ParameterizedTypeName.get(ClassName.get(Map.class),
ClassName.get(Integer.class),
WildcardTypeName.subtypeOf(TypeVariableName.get("T"))),
"map")
.addException(IOException.class)
.addException(RuntimeException.class)
.addCode(codeBlock)
.build();
}

/**
* ‘method’ 方法中的具体语句
*/
private static CodeBlock code() {
return CodeBlock.builder()
.addStatement("int foo = 1")
.addStatement("$T bar = $S", String.class, "a string")

// Object obj = new HashMap<Integer, ? extends T>(5);
.addStatement("$T obj = new $T(5)",
Object.class, ParameterizedTypeName.get(ClassName.get(HashMap.class),
ClassName.get(Integer.class),
WildcardTypeName.subtypeOf(TypeVariableName.get("T"))))

// method(new Runnable(String param) {
// @Override
// void run() {
// }
// });
.addStatement("baz($L)", TypeSpec.anonymousClassBuilder("$T param", String.class)
.superclass(Runnable.class)
.addMethod(MethodSpec.methodBuilder("run")
.addAnnotation(Override.class)
.returns(TypeName.VOID)
.build())
.build())

// for
.beginControlFlow("for (int i = 0; i < 5; i++)")
.endControlFlow()

// while
.beginControlFlow("while (false)")
.endControlFlow()

// do... while
.beginControlFlow("do")
.endControlFlow("while (false)")

// if... else if... else...
.beginControlFlow("if (false)")
.nextControlFlow("else if (false)")
.nextControlFlow("else")
.endControlFlow()

// try... catch... finally
.beginControlFlow("try")
.nextControlFlow("catch ($T e)", Exception.class)
.addStatement("e.printStackTrace()")
.nextControlFlow("finally")
.endControlFlow()

.addStatement("return 0")
.build();
}

这样就省去了我们自己手动评价代码块的麻烦,提高效率,并且也比较容易查错。

反射

这玩意说起来可就长了,这里只做示例

一个Person类

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
package com.huangyuanlove;

public class Person {
private int age;
public String name;

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getAddress(){
return "getAddress without param";
}

private String getAddress(String zipCode){
return "getAddress with param:" + zipCode;
}

private Person() {
}
}

玩一下反射

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
package com.huangyuanlove;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Main {

public static void main(String[] args) {

try {
//如果没有对应类的依赖的话(不能直接import),可以用Class.forName
//Class personClass = Class.forName("com.huangyuanlove.Person");
Class<Person> personClass = Person.class;

//调用私有无参构造方法创建对象
Constructor<Person> personConstructor = personClass.getDeclaredConstructor();
personConstructor.setAccessible(true);
Person person = personConstructor.newInstance();
//反射获取公共方法并调用
Method getAddressWithoutParamMethod = personClass.getMethod("getAddress");
System.out.println( getAddressWithoutParamMethod.invoke(person));

//反射获取私有方法并调用
Method getAddressMethod = personClass.getDeclaredMethod("getAddress", String.class);
getAddressMethod.setAccessible(true);
System.out.println(getAddressMethod.invoke(person, "zipCode"));

//反射获取私有字段并赋值
Field ageField = personClass.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(person,11);
System.out.println(person.getAge());

//反射获取私有静态方法并调用
Method sayHiMethod = personClass.getDeclaredMethod("saySomething",String.class);
sayHiMethod.setAccessible(true);
sayHiMethod.invoke(null,"reflect");


} catch (Exception e) {
e.printStackTrace();
}

}
}

以上