ButterKnife使我們經(jīng)常使用的一款View注入框架,使用方便,特點(diǎn)是ButterKnife使用的是編譯時(shí)生成代碼,而不是反射注入。那么我就有一個(gè)問(wèn)題,ButterKnife究竟是如何在編譯時(shí)生成代碼的呢?這就是這篇文章的目的了。。。
先做一個(gè)例子我們來(lái)試著在編譯時(shí)做一些操作。
介紹幾個(gè)概念
1.APT
APT-annotation processing tool是在編譯時(shí),掃描和處理注解的一個(gè)構(gòu)建工具,該工能由 javac 來(lái)實(shí)現(xiàn),我們可以在 javac 編譯時(shí)源代碼額外生成 java 源代碼(也可以是其它類(lèi)型的文件)。關(guān)于如何處理注解我們需要了解AbstractProcessor這個(gè)類(lèi)。Annotation Processor的實(shí)現(xiàn),都需要繼承自該類(lèi)。
2.AbstractProcessor
AbstractProcessor 是 javac 掃描和處理注解的關(guān)鍵類(lèi)。介紹兩個(gè)關(guān)鍵的方法,
(1)public Set<String> getSupportedAnnotationTypes()
制定需要處理哪些注解 ,返回值是注解全類(lèi)名的Set。
(2)public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)
Processor的主方法,可以在該方法中處理注解,并生成Java代碼,并可以通過(guò)RoundEnvironment獲取到被注解的元素。
先創(chuàng)建三個(gè)Module
1.app (Android Module已存在)
2.api (Java Module存放我們的注解)
3.compiler (Java Module 存放我們的Processor)
聲明插件依賴(lài)
聲明插件android-apt,這個(gè)是Android Studio 與annotation processors結(jié)合的一個(gè)插件,在構(gòu)建工程時(shí)將輔助javac執(zhí)行processor, 在根目錄的build.gradle添加:
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
api Module
定義注解
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
}
app module
在app的build.gradle:
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
...
compile project(':api')
apt project(':compiler')
...
}
使用api中定義的注解
@MyAnnotation
public class Bean {
}
compiler module
在build.gradle:
apply plugin: 'java'
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.google.auto.service:auto-service:1.0-rc3'
compile 'com.squareup:javapoet:1.8.0'
compile project(':api')
}
這里添加了三個(gè)依賴(lài)
1.api: 我們需要獲取到我們定義的MyAnnotation注解
2.auto-service:用來(lái)自動(dòng)生成 javax.annotation.processing.Processor 文件。location:https://github.com/google/auto/tree/master/service
3.javapoet:自動(dòng)生成代碼的工具類(lèi)庫(kù)。location:https://github.com/square/javapoet
然后創(chuàng)建我們的Processor類(lèi)。
@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor {
@Override
public Set<String> getSupportedAnnotationTypes() {
return Collections.singleton(MyAnnotation.class.getCanonicalName());
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
System.out.println("Message");
return true;
}
}
這時(shí)clean下Project 然后運(yùn)行./gradlew assemble就可以看到輸出的Message。
JavaPoet是一個(gè)用來(lái)生成.java源文件的Java API。