Android注解支持(Support Annotations)

注解支持(Support Annotations)

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

使用注解庫

注解默認是沒有包含的;他們被包裝成一個獨立的庫。(support library現在由一些更小的庫組成:v4-support, appcompat, gridlayout, mediarouter等等)

(如果你正在使用appcompat庫,那么你已經可以使用這些注解了,因為appcomat它自己也依賴它。)

添加使用注解最簡單的方式就是打開Project Structure對話框。首先在左邊選中module,然后在右邊選中Dependencies標簽頁,點擊面板底部的+按鈕,選擇Library Dependency,假設你已經把Android Support Repository安裝到你的SDK中了,那么注解庫將會出現在列表中,你只需點擊選中它即可(這里是列表中的第一個)

添加依賴
點擊OK完成Project Structure的編輯。這會修改你的build.gradle文件,當然你也可以手動編輯它:
dependencies { compile 'com.android.support:support-annotations:22.2.0'}

對于Android application和Android library這兩個類型的module(你應用了com.android.application或者com.android.library插件的)來說,你需要做的已經都做好了。如果你想只在Java module使用這些注解,那么你就明確的包含SDK倉庫了,因為support libraries不能從jcenter獲得(Android Gradle插件會自動的包含這些依賴,但是Java插件卻沒有。)

repositories {
   jcenter() 
   maven {
        url '<your-SDK-path>/extras/android/m2repository'
   }
}
執行注解

當你用Android Studio和IntelliJ的時候,如果給標注了這些注解的方法傳遞錯誤類型的參數,那么IDE就會實時標記出來。

從Gradle插件1.3.0-beta1版本開始,并且安裝了Android M Preview平臺工具的情況下,通過命令行調用gradle的lint
任務就可以執行這些檢查。如果你想把標記問題作為持續集成的一部分,那么這種方式是非常有用的。說明:這并不包含nullness注解。本文中所介紹的其他注解都可以通過lint執行檢查。

Nullness Annotations

@Nullable注解能被用來標注給定的參數或者返回值可以為null。
類似的,@NonNull注解能被用來標注給定的參數或者返回值不能為null。

如果一個本地變量的值為null(比如因為過早的代碼檢查它是否為null),而你又把它作為參數傳遞給了一個方法,并且該方法的參數又被@NonNull標注,那么IDE會提醒你,你有一個潛在的崩潰問題。

   v4 support library中的FragmentActivity的示例代碼:

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
...
/** 
* Add support for inflating the <fragment> tag. 
*/
@Nullable
@Override
public View onCreateView(String name, @NonNull Context context, @NonNull AttributeSet attrs) {
...

(如果你執行Analyze > Infer Nullity,或者你在鍵入時把@NonNull替換成了@NotNull,那么IDE可能會提供附加的IntelliJ注解。參考底部的“IntelliJ Annotations”段落了解更多)

注意@NonNull和@Nullable并不是對立的:還有第三種可能:未指定。當你沒有指定@NonNull或者@Nullable的時候,工具就不能確定,所以這個API也就不起作用。

最初,我們在findViewById方法上標注@Nullable,從技術上說,這是正確的:findViewById可以返回null。但是如果你知道你在做什么的時候(如果你傳遞給他一個存在的id)他是不會返回null的。當我們使用@Nullable注解它的時候,就意味著源代碼編輯器中會有大量的代碼出現高亮警告。如果你已經意識到每次使用該方法都應該明確的進行null檢查,那么就只能用@Nullable標注返回值。有個經驗規則:看現有的“好的代碼”(比如審查產品代碼),看看這些API是怎么被使用的。如果該代碼為null檢查結果,你應該為方法注解@Nullable。

資源類型注解

Android的資源值通常都是使用整型傳遞。這意味著獲取一個drawable使用的參數,也能很容易的傳遞給一個獲取string的方法;因為他們都是int類型,編譯器很難區分。

資源類型注解可以在這種情況下提供類型檢查。比如一個被@StringRes住進誒的int類型參數,如果傳遞一個不是R.string類型的引用將會被IDE標注:


資源類型注解以ActionBar為例:

import android.support.annotation.StringRes;
...public abstract void setTitle(@StringRes int resId);

有`很多不同資源類型的注解:如下的每一個Android資源類型:
@StringRes, @DrawableRes, @ColorRes, @InterpolatorRes,等等。一般情況下,如果有一個foo
類型的資源,那么它的相應的資源類型注解就是FooRes.

除此之外,還有一個名為@AnyRes特殊的資源類型注解。它被用來標注一個未知的特殊類型的資源,但是它必須是一個資源類型。比如在框架中,它被用在Resources#getResourceName(@AnyRes int resId)上,使用的時候,你可以這樣getResources().getResourceName(R.drawable.icon)用,也可以getResources().getResourceName(R.string.app_name)這樣用,但是卻不能這樣getResources().getResourceName(42)用。

請注意,如果你的API支持多個資源類型,你可以使用多個注解來標注你的參數。

IntDef/StringDef: 類型定義注解

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

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

appcompat庫里的一個例子:

import android.support.annotation.IntDef;
...
public abstract class ActionBar {
...
@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
@Retention(RetentionPolicy.SOURCE)
public @interface NavigationMode {}

public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;

@NavigationMode
public abstract int getNavigationMode();

public abstract void setNavigationMode(@NavigationMode int mode);

上面非注解的部分是現有的API。我們創建了一個新的注解(NavigationMode)并且用@IntDef標注它,通過@IntDef我們為返回值或者參數指定了可用的常量值。我們還添加了@Retention(RetentionPolicy.SOURCE)告訴編譯器這個新定義的注解不需要被記錄在生成的.class文件中(譯者注:源代碼級別的,生成class文件的時候這個注解就被編譯器自動去掉了)。

使用這個注解后,如果你傳遞的參數或者返回值不在指定的常量值中的話,IDE將會標記出這種情況。

你也可以指定一個整型是一個標記性質的類型;這樣客戶端代碼就通過|,&等操作符同時傳遞多個常量了:

@IntDef(flag=true, value={ 
    DISPLAY_USE_LOGO,
    DISPLAY_SHOW_HOME, 
    DISPLAY_HOME_AS_UP,
    DISPLAY_SHOW_TITLE, 
    DISPLAY_SHOW_CUSTOM
})

@Retention(RetentionPolicy.SOURCE)
public @interface DisplayOptions {}

最后,還有一個字符串版本的注解,就是@StringDef,它和@IntDef的作用基本上是一樣,所不同的是它是針對字符串的。該注解一般不常用,但是有的時候非常有用,比如在限定向Activity#getSystemService方法傳遞的參數范圍的時候。

要了解關于類型注解的更多詳細信息,請參考https://developer.android.com/tools/debugging/annotations.html#enum-annotations

(這些都是建立在IntelliJ’s MagicConstant注解的基礎上,你可以在這里找到該注解的詳細信息:http://blog.jetbrains.com/idea/2012/02/new-magic-constant-inspection/)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容