你必須知道的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'}
- 1
- 2
- 3
- 4
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' }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
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'}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
基本使用就是上面這兩點,想用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
- 1
- 2
- 3
- 4
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 {}
- 1
- 2
- 3
- 4
- 5
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; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
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'}
- 1
- 2
- 3
- 4
- 5
至此一個簡單的自定義註解類,就完成了,只是生成了一個HelloWorld.java檔案,裡面只有一個main()函式
6.3、自定義註解類的使用
使用的話,更簡單。在java檔案中使用如下:
@AutoCreatpublic class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
配置build.gradle檔案
dependencies { //新增下面這句就可以了 compile project(":apt-lib") annotationProcessor project(':apt-process')}
- 1
- 2
- 3
- 4
- 5
- 6
參考:
關注我的公眾號,輕鬆瞭解和學習更多技術