如今 Android 主流庫中使用 apt 的愈來愈多,如Dagger2,ButterKnife,DBflow等。不研究一下其怎麼玩的,內心實在是不舒服斯基,因此就有了這篇apt代碼簡單生成的文章。文章的末尾,會附上一些關於註解的基礎知識,有興趣的童鞋能夠再去看看。html
首先,咱們得須要新建一個名稱爲annotation的Java Library。這裏簡單的建一個@interfact
的註解類便可。以下:java
@Target(ElementType.TYPE) @Retention(RetentionPolicy.CLASS) public @interface Test { String value(); }
能夠看到的是,這是編譯時期的註解,主要做用於Class。以後,在調用的地方就是須要使用咱們的這個註解。android
這裏,也使用的是Java Library,咱們把報名定爲 compiler,先定義gradle文件:git
apply plugin: 'java' sourceCompatibility = 1.7 targetCompatibility = 1.7 dependencies { compile 'com.google.auto.service:auto-service:1.0-rc2' compile 'com.squareup:javapoet:1.7.0' compile project(':annotation') }
代碼中,引入兩個庫,AutoService主要的做用是註解processor
類,並對其生成 META-INF 的配置信息。github
JavaPoet這個庫的主要做用就是幫助咱們經過類調用的形式來生成代碼。app
創建一個名稱爲TestProcessor的類,以下:ide
@AutoService(Processor.class) public class TestProcessor extends AbstractProcessor { @Override public Set<String> getSupportedAnnotationTypes() { return Collections.singleton(Test.class.getCanonicalName()); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { return false; } }
其中要注意的是使用AutoSerivce
的註解,這樣就不用再手動配置 META-INF文件了。方法getSupportedAnnotationTypes
則是定義咱們針對生成的註解類,方法process
則是咱們的重頭戲,其中則是咱們生成代碼的主要邏輯之處:學習
@Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { Set<? extends Element> set = roundEnv.getElementsAnnotatedWith(Test.class); for (Element element : set) { if (element.getKind() != ElementKind.CLASS) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "only support class"); } MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class) .addParameter(String[].class, "args") .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!") .build(); TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld").addModifiers(Modifier.PUBLIC, Modifier.FINAL).addMethod(main).build(); JavaFile javaFile = JavaFile.builder("com.lighters.apt", helloWorld).build(); try { javaFile.writeTo(processingEnv.getFiler()); } catch (IOException e) { e.printStackTrace(); } } return false; }
這裏簡單使用JavaPoet文檔中的第一個example, 生成一個簡單的HelloWorld類。你們可本身行去查看JavaPoet的更多用法,支持各類姿式生成Java的代碼,並與Processor
完美契合。gradle
準備工做都完成以後,接下來就在咱們的主目錄app下面,經過添加註解,來查看咱們的代碼生成邏輯。ui
在根目錄的build.gradle
文件中的dependencies
節點下面添加以下代碼:
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
app的build.gradle
中添加以下代碼:
apply plugin: 'com.neenbedankt.android-apt' dependencies { compile project(':annotation') apt project(':compiler') }
這裏,就偷一個小懶,在MainActivity
上,添加註解Test
,格式以下:
@Test("haha") public class MainActivity extends AppCompatActivity { }
注意,這裏定義的註解爲編譯期的註解,因此代碼的生成,只須要經過執行Rebuild便可。執行完成以後,在app的build/generated/source/apt目錄下,便可看到我們的代碼,如圖:
apt代碼的生成是定義編譯期的註解,再經過繼承Proccesor
實現代碼生成邏輯,實現了編譯期生成代碼的邏輯。相對於在運行期經過反射來講,提升了程序的運行速度。這裏只是簡單引導你們搭建本身的apt處理器,更多的內容期待你們各自玩出花來。
附上一篇標準的編譯期代碼生成,以及trinea關於annotation的詳細介紹。
另外,使用apt的代碼庫Dagger2, Butterknife你們可自行深刻研究了。
轉載請註明原文連接: http://alighters.com/blog/2016/05/10/apt-code-generate/