今天试着写一下ButterKnife的原理,虽然网上已经有很多说的了,但是代码还是要亲手打出来,而且网上都是旧版本的gradle,仍然用的apt插件,gradle 3.0已经不需要了,而且是不能用apt了
因为代码部分比较简单,所以只写一下步骤。
创建一个Android项目,名字随意,Android Studio会在这个项目创建一个默认模块app 。
创建一个新的模块annotation,并且在模块里面创建一个注解类AnnotationFIELD
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18package com.example.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.CLASS;
/**
* Created by alan on 2017/12/2.
*/
public AnnotationFIELD {
int value() default 0;
}并且在此模块的build.gradle文件末尾增加
1
2
3sourceCompatibility = "1.7"
targetCompatibility = "1.7"创建一个新的模块processor,并且在模块里面创建一个注解处理器MyProcessor
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
72package com.example.processor;
import com.example.annotation.AnnotationFIELD;
import com.google.auto.service.AutoService;
import java.io.IOException;
import java.io.Writer;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
/**
* Created by alan on 2017/12/2.
*/
public class MyProcessor extends AbstractProcessor {
static final String CLASS_NAME = "GeneratedClass";
final String PACKAGENAME = this.getClass().getPackage().getName();
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
StringBuilder builder = new StringBuilder()
.append("package ")
.append(PACKAGENAME)
.append(";\n\n")
.append("public class " + CLASS_NAME + " {\n\n") // open class
.append("\tpublic String getMessage() {\n") // open method
.append("\t\treturn \"");
// for each javax.lang.model.element.Element annotated with the AnnotationFIELD
for (Element element : roundEnvironment.getElementsAnnotatedWith(AnnotationFIELD.class)) {
String objectType = element.getSimpleName().toString();
printMessageInGradleConsole("====objectType :==== " + objectType);
// this is appending to the return statement
builder.append(objectType).append(" says hello! ");
}
builder.append("\";\n") // end return
.append("\t}\n") // close method
.append("}\n"); // close class
printMessageInGradleConsole("Package : " + PACKAGENAME);
try { // write the file
JavaFileObject source = processingEnv.getFiler().createSourceFile(PACKAGENAME + "." + CLASS_NAME);
Writer writer = source.openWriter();
writer.write(builder.toString());
writer.flush();
writer.close();
} catch (IOException e) {
// Note: calling e.printStackTrace() will print IO errors
// that occur from the file already existing after its first run, this is normal
}
return true;
}
void printMessageInGradleConsole(String str){
//processingEnv是父类的成员变量
processingEnv.getMessager().printMessage(Diagnostic.Kind.MANDATORY_WARNING,str);
}
}然后修改这个模块的build.gradle文件:
1
2
3
4
5
6
7
8
9
10apply plugin: 'java-library'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.google.auto.service:auto-service:1.0-rc3'
implementation project(':annotation')
}
sourceCompatibility = "1.7"
targetCompatibility = "1.7"
之前不能生成对应的 .class文件,就是在这里卡了一下。主要注意的地方有以下几个:
Java的版本,1.7和1.8都可以
AutoService注解,别的地方说,添加了之后不需要设置meta文件夹了,我看Butterknife的项目里面也只加了这一行,但是我这里仍然需要@SupportedAnnotationTypes(“com.example.annotation.AnnotationFIELD”)
@SupportedSourceVersion(SourceVersion.RELEASE_8) _这两个注解,不然无法生成类,(或者重写对应的方法 );
SourceVersion,RELEASE_7或8都可以
在最开始的模块,app模块的build.gradle里面加入
1
2
3
4
5
6
7
8
9
10Android{
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies{
implementation project(':annotation')
annotationProcessor project(':processor')
}这里要说明的是,虽然在本地建立了processor模块,但是实际上并不需要implementation,只需要annotationProcessor就行了,这个和Butterknife的处理也是一致的,而且也不需要apt插件了
在app模块下的MainActivity类增加声明
1
2
private TextView textView;这里只需要用一下注解就好
clean Project,Rebuild Project ,这时候应该可以在
1
app\build\generated\source\apt\debug
目录下找到GeneratedClass这个生成类了
相应的代码在github上,打了tag v0.1