你必須知道的APT、annotationProcessor、android-apt、Provided、自定義註解
你可能經常在build.gradle檔案中看到,這樣的字眼,annotationProcessor、android-apt、Provided,它們到底有什麼作用?下面就一起來看看吧
1、什麼是APT?
隨著一些如ButterKnife,dagger等的開源註解框架的流行,APT的概念也越來越被熟知。
annotationProcessor和android-apt的功能是一樣的,它們是替代關係,在認識它們之前,先來看看APT。
APT(Annotation Processing Tool)是一種處理註釋的工具,它對原始碼檔案進行檢測找出其中的Annotation,根據註解自動生成程式碼。 Annotation處理器在處理Annotation時可以根據原始檔中的Annotation生成額外的原始檔和其它的檔案(檔案具體內容由Annotation處理器的編寫者決定),APT還會編譯生成的原始檔和原來的原始檔,將它們一起生成class檔案。
APT的處理要素
註解處理器(AbstractProcess)+程式碼處理(javaPoet)+處理器註冊(AutoService)+apt
使用APT來處理annotation的流程
1. 定義註解(如@automain)
2. 定義註解處理器,自定義需要生成程式碼
3.使用處理器
4.APT自動完成如下工作。
2、annotationProcessor
annotationProcessor是APT工具中的一種,他是google開發的內建框架,不需要引入,可以直接在build.gradle檔案中使用,如下
dependencies {
annotationProcessor project(':xx' )
annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
}
3、android-apt
android-apt是由一位開發者自己開發的apt框架,原始碼託管在這裡,隨著Android Gradle 外掛 2.2 版本的釋出,Android Gradle 外掛提供了名為 annotationProcessor 的功能來完全代替 android-apt ,自此android-apt 作者在官網發表宣告最新的Android Gradle外掛現在已經支援annotationProcessor,並警告和或阻止android-apt ,並推薦大家使用 Android 官方外掛annotationProcessor。
但是很多專案目前還是使用android-apt,如果想替換為annotationProcessor,那就要知道android-apt是如何使用的。下面就來介紹一下
3.1、新增android-apt到Project下的build.gradle中
//配置在Project下的build.gradle中
buildscript {
repositories {
mavenCentral()
}
dependencies {
//替換成最新的 gradle版本
classpath 'com.android.tools.build:gradle:1.3.0'
//替換成最新android-apt版本
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
3.2、在Module中build.gradle的配置
通常在使用的時候,使用apt宣告註解用到的庫檔案。專案依賴可能分為多個部分。例如Dagger有兩個元件Dagger-compiler和dagger。dagger-commpiler僅用於編譯時,執行時必需使用dagger。
//配置到Module下的build.gradle中
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
apt 'com.squareup.dagger:dagger-compiler:1.1.0'
compile 'com.squareup.dagger:dagger:1.1.0'
}
基本使用就是上面這兩點,想用annotationProcessor替代android-apt。刪除和替換相應部分即可
4、Provided 和annotationProcessor區別
annotationProcessor
只在編譯的時候執行依賴的庫,但是庫最終不打包到apk中,
編譯庫中的程式碼沒有直接使用的意義,也沒有提供開放的api呼叫,最終的目的是得到編譯庫中生成的檔案,供我們呼叫。
Provided
Provided 雖然也是編譯時執行,最終不會打包到apk中,但是跟apt/annotationProcessor有著根本的不同。
A 、B、C都是Library。
A依賴了C,B也依賴了C
App需要同時使用A和B
那麼其中A(或者B)可以修改與C的依賴關係為Provided
A這個Library實際上還是要用到C的,只不過它知道B那裡也有一個C,自己再帶一個就顯得多餘了,等app開始執行的時候,A就可以通過B得到C,也就是兩人公用這個C。所以自己就在和B匯合之前,假設自己有C。如果執行的時候沒有C,肯定就要崩潰了。
總結一下,Provided是間接的得到了依賴的Library,執行的時候必須要保證這個Library的存在,否則就會崩潰,起到了避免依賴重複資源的作用。
5、自定義註解
6、使用APT的簡單專案——自定義註解
6.1、新增一個java Library Module 名為apt-lib, 編寫註解類:
@Target(ElementType.TYPE) //作用在類上
@Retention(RetentionPolicy.RUNTIME)//存活時間
public @interface AutoCreate {
}
6.2、新增一個java Library Module 名為apt-process,編寫類來處理註解。以後使用上面的@AutoCreate,就會根據下面這個類生成指定的java檔案
@AutoService(Processor.class)
public class TestProcess extends AbstractProcessor {
@Override
public Set<String> getSupportedAnnotationTypes() {
return Collections.singleton(AutoCreat.class.getCanonicalName());
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
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.songwenju.aptproject", helloWorld)
.build();
try {
javaFile.writeTo(processingEnv.getFiler());
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}
6.2.1、需要使用的lib
dependencies {
compile project(':apt-lib')
compile 'com.squareup:javapoet:1.8.0'
compile 'com.google.auto.service:auto-service:1.0-rc2'
}
至此一個簡單的自定義註解類,就完成了,只是生成了一個HelloWorld.java檔案,裡面只有一個main()函式
6.3、自定義註解類的使用
使用的話,更簡單。在java檔案中使用如下:
@AutoCreat
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
配置build.gradle檔案
dependencies {
//新增下面這句就可以了
compile project(":apt-lib")
annotationProcessor project(':apt-process')
}
參考:
關注我的公眾號,輕鬆瞭解和學習更多技術