本文講的是Android註解快速入門和實用解析,首先什麼是註解?@Override就是註解,它的做用是:java
一、體如今於:檢查子類重寫的方法名與參數類型是否正確;檢查方法private/final/static等不能被重寫。實際上@Override對於應用程序並無實際影響,從它的源碼中能夠出來。android
二、主要是表現出代碼的可讀性。緩存
做爲Android開發中熟知的註解,Override只是註解的一種體現,更多時候,註解還有如下做用:數據結構
1、註解基礎快讀ide
一、元註解工具
元註解是由java提供的基礎註解,負責註解其它註解,如上圖Override被@Target和@Retention修飾,它們用來講明解釋其它註解,位於sdk/sources/android-25/java/lang/annotation路徑下。this
元註解有:google
@Retention3d
Retention說標明瞭註解被生命週期,對應RetentionPolicy的枚舉,表示註解在什麼時候生效:對象
以下圖X1,com.android.support:support-annotations中的Nullable註解,會在編譯期判斷,被註解的參數是否會空,具體後續分析。
@Target
Target標明瞭註解的適用範圍,對應ElementType枚舉,明確了註解的有效範圍。
如上圖X1所示,@Nullable可用於註解方法,參數,類成員,註解,包聲明中,經常使用例子以下所示:
@Inherited
註解所做用的類,在繼承時默認沒法繼承父類的註解。除非註解聲明瞭 @Inherited。同時Inherited聲明出來的注,只對類有效,對方法/屬性無效。
以下方代碼,註解類@AInherited聲明瞭Inherited ,而註解BNotInherited 沒有,所在在它們的修飾下:
二、自定義註解
2.1 運行時註解
瞭解了元註解後,看看如何實現和使用自定義註解。這裏咱們簡單介紹下運行時註解RUNTIME,編譯時註解CLASS留着後面分析。
首先,建立一個註解遵循: public @interface 註解名 {方法參數},以下方@getViewTo註解:
而後以下方所示,咱們將註解描述在Activity的成員變量mTv和mBtn中,在App運行時,經過反射將findViewbyId獲得的控件,注入到mTv和mBtn中。
是否是很熟悉,有點ButterKnife的味道?固然,ButterKnife比這個高級多,畢竟反射多了影響效率,不過咱們明白了,能夠經過註解來注入和建立對象,這樣能夠在必定程度節省代碼量。
2.2 編譯時註解
運行時註解RUNTIME如上2.1所示,大多數時候實在運行時使用反射來實現所需效果,這很大程度上影響效率,若是BufferKnife的每一個View注入不可能如何實現。實際上,ButterKnife使用的是編譯時註解CLASS,以下圖X2.2,是ButterKnife的@BindView註解,它是一個編譯時註解,在編譯時生成對應java代碼,實現注入。
說到編譯時註解,就不得不說註解處理器 AbstractProcessor,若是你有注意,通常第三方註解相關的類庫,如bufferKnike、ARouter,都有一個Compiler命名的Module,以下圖X2.3,這裏面通常都是註解處理器,用於編譯時處理對應的註解。
註解處理器(Annotation Processor)是javac的一個工具,它用來在編譯時掃描和處理註解(Annotation)。你能夠對自定義註解,並註冊相應的註解處理器,用於處理你的註解邏輯。
以下所示,實現一個自定義註解處理器,至少重寫四個方法,而且註冊你的自定義Processor,詳細可參考下方代碼CustomProcessor。
首先,咱們梳理下通常處理器處理邏輯:
而後,讓咱們理解一個概念:Element,由於它是咱們獲取註解的基礎。
Processor處理過程當中,會掃描所有Java源碼,代碼的每個部分都是一個特定類型的Element,它們像是XML一層的層級機構,好比類、變量、方法等,每一個Element表明一個靜態的、語言級別的構件,以下方代碼所示。
其中,Element表明的是源代碼,而TypeElement表明的是源代碼中的類型元素,例如類。然而,TypeElement並不包含類自己的信息。你能夠從TypeElement中獲取類的名字,可是你獲取不到類的信息,例如它的父類。這種信息須要經過TypeMirror獲取。你能夠經過調用elements.asType()獲取元素的TypeMirror。
一、知道了Element,咱們就能夠經過process 中的RoundEnvironment去獲取,掃描到的全部元素,以下圖X2.4,經過env.getElementsAnnotatedWith,咱們能夠獲取被@BindView註解的元素的列表,其中validateElement校驗元素是否可用。
二、由於env.getElementsAnnotatedWith返回的,是全部被註解了@ BindView的元素的列表。因此有時候咱們還須要走一些額外的判斷,好比,檢查這些Element是不是一個類:
三、javapoet (com.squareup:javapoet)是一個根據指定參數,生成java文件的開源庫,有興趣瞭解javapoet的能夠看下javapoet——讓你從重複無聊的代碼中解放出來,在處理器中,按照參數建立出 JavaFile以後,通Filer利用javaFile.writeTo(filer);就能夠生成你須要的java文件。
四、錯誤處理,在處理器中,咱們不能直接拋出一個異常,由於在process()中拋出一個異常,會致使運行註解處理器的JVM崩潰,致使跟蹤棧信息十分混亂。所以,註解處理器就有一個Messager類,通常經過messager.printMessage( Diagnostic.Kind.ERROR, StringMessage, element)便可正常輸出錯誤信息。
至此,你的註解處理器完成了全部的邏輯。能夠看出,編譯時註解實在編譯時生成java文件,而後將生產的java文件注入到源碼中,在運行時並不會像運行時註解同樣,影響效率和資源。
總結
咱們就利用ButterKnife的流程,簡單舉例作個總結吧。
好了,經過上面的流程,是否是把編譯時註解的生成和使用鏈接起來了呢?有問題還請各位留言談論。