Android 學習使用annotationprocessor自動生成java文件

最近看glide源碼,發現裏面有個類必須用到的,沒在源碼裏面,竟然在build/generated目錄下,這裏面是自動生成的Java文件,好比R文件。java

奇了個怪了,經過查閱大神文章知道了原來是利用了annotationprocessor編譯器,在編譯期間建立的,用到這個的出名框架好比:Butter Knife、Glide  。android


注意:android-apt這個插件官方已經宣佈再也不維護,插件gradle2.2以上的版本使用annotationprocessor,因此咱們這裏跟着官方走。app

不然報錯:框架

如今咱們來生成一個超級簡單的Java文件吧ide

首先建立一個安卓項目如圖:函數

主工程build.gradle文件以下工具


apply plugin: 'com.android.application'
 
android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "com.example.alex.annotationprocessordemo"
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    annotationProcessor project(':Compiler')
}gradle

接下來建立一個Java Library  Moduleui


取好Module名字後以下圖:google

這裏要注意,Module類型是Java Library,不要選成Android Library

編輯build.gradle後的樣子以下:

apply plugin: 'java-library'
 
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    // 用於生成Java文件的庫
    compile 'com.squareup:javapoet:1.7.0'
    compile 'com.google.auto.service:auto-service:1.0-rc2'
}
sourceCompatibility = "1.7"
targetCompatibility = "1.7"

上面2個庫必定要的,記得加上

接下來在Compiler這個module中建立一個類MyProcessor.java


package com.example.alex.compiler;
 
import com.google.auto.service.AutoService;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;
import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
 
 
/**
 * @AutoService(Processor.class)
 * 這個註解不要忘了,不然沒法生成Java文件
 */
@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor{
 
    /**
     * 文件相關的輔助類
     */
    private Filer mFiler;
    /**
     * 元素相關的輔助類
     */
    private Elements mElementUtils;
    /**
     * 日誌相關的輔助類
     */
    private Messager mMessager;
 
    /**
     * 每個註解處理器類都必須有一個空的構造函數。
     * 然而,這裏有一個特殊的init()方法,它會被註解處理工具調用,
     * 並輸入ProcessingEnviroment參數。
     *
     * @param processingEnvironment
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        mElementUtils = processingEnv.getElementUtils();
        mMessager = processingEnv.getMessager();
        mFiler = processingEnv.getFiler();
    }
 
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
 
 
        // 類名和包名
        TypeSpec finderClass = TypeSpec.classBuilder("MyGeneratedClass")
                .addModifiers(Modifier.PUBLIC)
//                .addSuperinterface(ParameterizedTypeName.get(TypeUtil.INJECTOR, TypeName.get(mClassElement.asType())))
//                .addMethod(methodBuilder.build())
                .build();
 
        // 建立Java文件
        JavaFile javaFile = JavaFile.builder("com.example.alex.annotationprocessordemo", finderClass).build();
 
        try {
            javaFile.writeTo(mFiler);
        } catch (IOException e) {
            e.printStackTrace();
        }
 
 
        return true;
    }
 
    /**這個方法必須重寫,不然沒法生成Java文件
     * 這裏必須指定,這個註解處理器是註冊給哪一個註解的。
     * 注意,它的返回值是一個字符串的集合,包含本處理器想要處理的註解類型的合法全稱。
     * 換句話說,在這裏定義你的註解處理器註冊到哪些註解上。
     * @return
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types = new LinkedHashSet<>();
        types.add(Override.class.getCanonicalName());
//        types.add(OnClick.class.getCanonicalName());
        return types;
    }
}

重要函數解說

init(ProcessingEnvironment env): 每個註解處理器類都必須有一個空的構造函數。然而,這裏有一個特殊的init()方法,它會被註解處理工具調用,並輸入ProcessingEnviroment參數。ProcessingEnviroment提供不少有用的工具類Elements,Types和Filer。

public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env)這至關於每一個處理器的主函數main()。在這裏寫掃描、評估和處理註解的代碼,以及生成Java文件。輸入參數RoundEnviroment,可讓查詢出包含特定註解的被註解元素。

getSupportedAnnotationTypes();這裏必須指定,這個註解處理器是註冊給哪一個註解的。注意,它的返回值是一個字符串的集合,包含本處理器想要處理的註解類型的合法全稱。換句話說,在這裏定義你的註解處理器註冊到哪些註解上。 

getSupportedSourceVersion();用來指定你使用的Java版本。

這個類就是編譯期註解編譯器會根據它來建立Java文件,裏面提示的幾個必須加上的地方要注意,忘記了就建立不了文件。

到這裏基本工做都完成了,如今開始rebuild吧,成與不成就在於此了

看到了嗎?主工程中build/generated/source/apt/debug目錄下已經有了剛纔命名的MyGeneratedClass.java 

哈哈,若是生成了說明就大功告成,沒生成那麼再好好找下緣由是否是哪不對或者缺失了,如今又能夠愉快玩耍了

下面是demo連接

http://download.csdn.net/download/msn465780/10171779     點擊打開連接

相關文章
相關標籤/搜索