Android註解使用之使用Support Annotations註解優化程式碼

總李寫程式碼發表於2016-07-18

前言:

     前面學習總結了Java註解的使用,部落格地址詳見Java學習之註解Annotation實現原理,從本質上了解到什麼註解,以及註解怎麼使用?不要看見使用註解就想到反射會影響效能之類,今天我們就來學習一下Android Support Annotations註解來優化我們的程式碼,增加可讀性的同時,也讓讓更多的錯誤消滅在萌芽之中。

Support Annotations簡介:

    Android support library從19.1版本開始引入了一個新的註解庫,它包含很多有用的元註解,你能用它們修飾你的程式碼,幫助你發現bug。Support library自己本身也用到了這些註解,所以作為support library的使用者,Android Studio已經基於這些註解校驗了你的程式碼並且標註其中潛在的問題。

Support Annotations如何引入:

  註解預設是沒有包含的;它被包裝成一個獨立的庫,如果使用了appcompat庫,那麼Support Annotations就會自動引入進來,因為appcompat使用了Support Annotations,如果沒有則需要在build.gradle中新增如下配置:

dependencies {
    compile 'com.android.support:support-annotations:23.4.0'
}

Support Annotations分類:

   1.)Nullness註解

    @Nullable註解可以用來標識特定的引數或者返回值可以為null。

    @NonNull註解可以用來標識引數不能為null。

    

    2.)Resource Type 註解

       資源在Android中作為整型值來傳遞。這意味著希望獲取一個drawable作為引數的程式碼很容易被傳遞了一個string型別的資源,因為他們資源id都是整型的,編譯器很難區分。Resource Type註解在這種條件下可以提供型別檢查,例如:

如果型別指定錯誤,編譯不會通過。

常見的Resource Type註解,使用方式都是指定一個integer的引數、成員變數、或者方法,檢查對應的資源型別。

  • AnimatorRes animator資源型別
  • AnimResanim資源型別
  • AnyRes:任意資源型別
  • ArrayResarray資源型別
  • AttrResattr資源型別
  • BoolResboolean資源型別
  • ColorRescolor資源型別
  • DimenResdimen資源型別。
  • DrawableResdrawable資源型別。
  • FractionResfraction資源型別
  • IdResid資源型別
  • IntegerResinteger資源型別
  • InterpolatorResinterpolator資源型別
  • LayoutReslayout資源型別
  • MenuResmenu資源型別
  • PluralsResplurals資源型別
  • RawResraw資源型別
  • StringResstring資源型別
  • StyleableResstyleable資源型別
  • StyleResstyle資源型別
  • TransitionRestransition資源型別
  • XmlResxml資源型別

  以上基本上包括了所有的資源型別,但是有時需要通過RGB顏色整型來設定顏色值,在這種情況下,你可以使用@ColorInt註解,表示你期望的是一個代表顏色的整數值,如果使用不對同樣也是編譯不通過

  3.)Threading 註解

   比如我們在專案中處理比較耗時的操作,需要制定在工作子執行緒中執行,可以使用Threading 註解,如果沒有在制定的執行緒中執行也是編譯不過的

    幾種Threading註解

  • @UiThread UI執行緒
  • @MainThread 主執行緒
  • @WorkerThread 子執行緒
  • @BinderThread  繫結執行緒

 4.)Typedef 註解:IntDef/StringDef

     整型除了可以作為資源的引用之外,也可以用作“列舉”型別使用。

     @IntDef和”typedef”作用非常類似,你可以建立另外一個註解,然後用@IntDef指定一個你期望的整型常量值列表,最後你就可以用這個定義好的註解修飾你的API了。

例如:需要自定義網路型別

    private final static int GET=0;
    private final static int POST=1;
    private final static int DELETE=2;
    private final static int PUT=3;
    @IntDef({GET, POST, DELETE,PUT})
    @Retention(RetentionPolicy.SOURCE)
    public @interface ReqType{}

需要在呼叫時只能傳入指定型別,如果傳入型別不對,編譯不通過

 

 5.)Value Constraints註解:@Size, @IntRange, @FloatRange

    在實際開發過程中,我們有時可能需要設定一個取值範圍,這時我們可以使用取值範圍註解來約束。

比如我們設定一個百分比,取值範圍為0-100,

 

對於資料、集合以及字串,你可以用@Size註解引數來限定集合的大小(當引數是字串的時候,可以限定字串的長度)。

舉幾個例子

  • 集合不能為空: @Size(min=1)
  • 字串最大隻能有23個字元: @Size(max=23)
  • 陣列只能有2個元素: @Size(2)
  • 陣列的大小必須是2的倍數 (例如圖形API中獲取位置的x/y座標陣列: @Size(multiple=2)
6.)Permissions 註解: @RequiresPermission

有時我們的方法呼叫需要呼叫者擁有指定的許可權,這時我們可以使用@RequiresPermission註解,

@RequiresPermission(Manifest.permission.SET_WALLPAPER)
public abstract void setWallpaper(Bitmap bitmap) throws IOException;

除了上面的單一使用方式,官方同時也給出瞭如下幾種使用場景

 (1)如果你至少需要許可權集合中的一個,你可以使用anyOf屬性

@RequiresPermission(anyOf = {
    Manifest.permission.ACCESS_COARSE_LOCATION,
    Manifest.permission.ACCESS_FINE_LOCATION})
public abstract Location getLastKnownLocation(String provider);

  (2)如果你同時需要多個許可權,你可以用allOf屬性

@RequiresPermission(allOf = {
    Manifest.permission.READ_HISTORY_BOOKMARKS, 
    Manifest.permission.WRITE_HISTORY_BOOKMARKS})
public static final void updateVisitedHistory(ContentResolver cr, String url, boolean real) ;

  (3)對於intents的許可權,可以直接在定義的intent常量字串欄位上標註許可權需求(他們通常都已經被@SdkConstant註解標註過了)

@RequiresPermission(android.Manifest.permission.BLUETOOTH)
public static final String ACTION_REQUEST_DISCOVERABLE =
            "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";

(4)對於content providers的許可權,你可能需要單獨的標註讀和寫的許可權訪問,所以可以用@Read或者@Write標註每一個許可權需求

@RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS))
@RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS))
public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks");
7.)Overriding Methods 註解: @CallSuper

如果你的API允許使用者重寫你的方法,但是呢,你又需要你自己的方法(父方法)在重寫的時候也被呼叫,這時候你可以使用@CallSuper標註

例如:Activity的onCreate函式

@CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState) 

用了這個後,當重寫的方法沒有呼叫父方法時,工具就會給予標記提示

8.)Return Values註解: @CheckResult

 如果你的方法返回一個值,你期望呼叫者用這個值做些事情,那麼你可以使用@CheckResult註解標註這個方法。

 這個在具體使用中用的比較少,除非特殊情況,比如在專案中對一個資料進行處理,這個處理比較耗時,我們希望呼叫該函式的呼叫者在不需要處理結果的時候,提示沒有使用,酌情刪除呼叫。

9.)其他註解

   Keep:指出一個方法在被混淆的時候應該被保留。

   VisibleForTesting:可註解一個類,方法,或變數,表示有更寬鬆的可見性,這樣它能夠有更寬泛的可見性,使程式碼可以被測試。

10.)IntelliJ註解

    IntelliJ,Android Studio就是基於它開發的,IntelliJ有一套它自己的註解;IntDef分析其實重用的是MagicConstant分析的程式碼,IntelliJ null分析其實用的是一組配置好的null註解。如果你執行Analyze > Infer Nullity…,它會試圖找出所有的null約束並新增他們。這個檢查有時會插入IntelliJ註解。你可以通過搜尋,替換為Android註解庫的註解,或者你也可以直接用IntelliJ註解。在build.gradle裡或者通過Project Structure對話方塊的Dependencies皮膚都可以新增如下依賴:

dependencies {
    compile 'com.intellij:annotations:12.0'
}

小結:

   經過查閱資料,系統了學習了Support Annotations註解,學以致用,通過這個Support Annotations可以提高程式碼可讀性,同時可以在類載入時就可以檢查一些錯誤,同時不會對效能有任何影響,因為Support Annotations中的註解的生命週期全部是RetentionPolicy.CLASS。接下來準備在專案中大量推廣使用。

 

相關文章