一囱修、AbstractProcessor
1捞烟,概述
注解分為編譯時(shí)注解和運(yùn)行時(shí)注解薄声,現(xiàn)在流行的主流框架ButterKnife当船,Retrofit,Dragger都是編譯時(shí)注解默辨。編譯時(shí)注解的核心依賴APT(Annotation Processing Tools)實(shí)現(xiàn)的德频,原理是在某些代碼元素上(如類型、函數(shù)缩幸、字段等)添加注解壹置,在編譯時(shí)編譯器會(huì)檢查AbstractProcessor的子類,并且調(diào)用process函數(shù)表谊,然后將添加了注解的所有元素都傳遞到process函數(shù)中钞护,使得開(kāi)發(fā)人員可以在編譯器進(jìn)行相應(yīng)的處理。
二铃肯、創(chuàng)建步驟
1患亿,首先使用Android Studio創(chuàng)建一個(gè)Android的project。然后開(kāi)始創(chuàng)建一個(gè)名為processor的java library押逼。 點(diǎn)擊file->new->new module如圖
我們需要?jiǎng)?chuàng)建一個(gè)非Android的library步藕,注意一定要選擇Java Library
這里我們?nèi)∶蠦utterKnifeProcessor
2,兼容性配置
在app的工程下的build.gradle,進(jìn)行配置
加入這句話
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
如圖:
3挑格,創(chuàng)建Annotation
創(chuàng)建annotation的Java moduel咙冗,里面放置注解類,如圖:
4漂彤,創(chuàng)建注解處理器
在process模塊下創(chuàng)建一個(gè)處理器雾消,這個(gè)繼承AbstractProcessor,如圖:
這個(gè)類上可以添加注解:
@SupportedAnnotationTypes的值為當(dāng)前類支持的注解的完整類路徑挫望,支持通配符立润。如圖也就是注解類的類路徑
@SupportedSourceVersion 標(biāo)識(shí)該處理器支持的源碼版本
該類的源碼:
@SupportedAnnotationTypes("com.example.BindView")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class ButterKnifeProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
StringBuilder builder = new StringBuilder()
.append("package com.example.generated;\n\n")
.append("public class GeneratedClass {\n\n") // open class
.append("\tpublic String getMessage() {\n") // open method
.append("\t\treturn \"");
// for each javax.lang.model.element.Element annotated with the CustomAnnotation
for (Element element : roundEnv.getElementsAnnotatedWith(BindView.class)) {
String objectType = element.getSimpleName().toString();
// this is appending to the return statement
builder.append(objectType).append(" says hello!\\n");
}
builder.append("\";\n") // end return
.append("\t}\n") // close method
.append("}\n"); // close class
try { // write the file
JavaFileObject source = processingEnv.getFiler().createSourceFile("com.example.generated.GeneratedClass");
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;
}
}```
***這里的process方法生成了一個(gè)Java文件,在上面的方法中我們想在這個(gè)生成這個(gè)類和類中的方法媳板,也就是上面StringBuilder 里面連接的字符串桑腮,用來(lái)測(cè)試,這里先不要管這個(gè)類是怎么生成的后面會(huì)說(shuō)的***
package com.example.generated;
public class GeneratedClass {
public String getMessage() {
return "mTextView says hello!\nmTextView1 says hello!\n";
}
}```
5,創(chuàng)建resource文件
創(chuàng)建好注解處理器后蛉幸,我們需要告訴編譯器在編譯的時(shí)候使用哪個(gè)注解處理器破讨,這里就需要?jiǎng)?chuàng)建javax.annotation.processing.Processor文件在processor模塊下,main目錄中創(chuàng)建一個(gè)resources文件夾奕纫,然后下邊在創(chuàng)建META-INF/services提陶,最后里邊一個(gè)javax.annotation.processing.Processor文件,如下:
這個(gè)txt文件下寫(xiě)下注解器的路徑匹层,如:
選擇上圖中紅色部分隙笆,就能將這個(gè)類的路徑copy出來(lái)
6,添加android-apt
在project下的build.gradle中添加apt插件
添加依賴:
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
再在app的build.gradle中添加
apply plugin: 'com.neenbedankt.android-apt'
7,設(shè)置build的依賴
注解處理器編譯生成一個(gè)jar撑柔,然后把這個(gè)jar包復(fù)制到app模塊下煤率。然后讓app依賴引用這個(gè)jar。
首先配置app的build.gradle依賴項(xiàng)
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.0'
compile 'com.android.support.constraint:constraint-layout:1.0.0-beta5'
compile project(':annotation')
apt project(':processor')
testCompile 'junit:junit:4.12'
}
然后我們編寫(xiě)一個(gè)gradle task乏冀,把生成的jar文件復(fù)制到app/libs目錄中蝶糯。
task processorTask(type: Copy) {
from '../processor/build/libs/processor.jar' into 'libs/'
}
processorTask.dependsOn(':processor:build')
preBuild.dependsOn(processorTask)
這里的processor是Java moduel的名字,換成你自己的名字即可
完整的build:
8辆沦,使用注解
先執(zhí)行Clean Project昼捍,然后再執(zhí)行ReBuild Project,如果BUILD SUCCESSFUL
當(dāng)然也可以在libs中看到生成的jar文件
如圖:
然后我們可以在下述位置查看到生成的Java文件
app/build/generated/source/apt/debug/package/GeneratedClass.java
如圖:
此時(shí)這個(gè)類的代碼是這個(gè)樣的
是不是在此時(shí),覺(jué)得很神奇肢扯,怎么在ButterKnifeProcessor 中process中StringBuilder連接的字符串怎么在這里生成了妒茬,
返回去看那個(gè)類的源碼,是不是思路一下的就清晰啦蔚晨,通過(guò)反射注解乍钻,編譯器在 rebuild的時(shí)候就會(huì)檢查ButterKnifeProcessor 這個(gè)類,調(diào)用process方法铭腕,所以效率是很高的
9银择,驗(yàn)證是否能使用
在app中的MainActivity中使用,代碼如下:
public class MainActivity extends AppCompatActivity {
@BindView(R.id.textView)
TextView mTextView;
@BindView(R.id.textView1)
TextView mTextView1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showMessage();
}
private void showMessage() {
GeneratedClass generatedClass = new GeneratedClass();
String message = generatedClass.getMessage();
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(message)
.setTitle("測(cè)試編譯時(shí)")
.setPositiveButton("ok", null).show();
}
}
下一篇:
http://www.reibang.com/p/c516036506fd
參考文檔
http://blog.stablekernel.com/the-10-step-guide-to-annotation-processing-in-android-studio