1. 程式人生 > >Android註解:Android 常用註解

Android註解:Android 常用註解

首先說一下在Android程式碼中使用註解的好處。使用註解向 Lint 之類的程式碼檢查工具提供提示,幫助檢測這些更細微的程式碼問題;還可以少寫一些重複程式碼;使用註解還非常的方便等等。

1 新增支援註解庫依賴項

支援註解庫是 Android 支援庫的一部分。要向您的專案添加註解,您必須下載支援儲存庫並向 build.gradle 檔案中新增 support-annotations 依賴項。

  • 開啟 SDK 管理器,方法是點選工具欄中的 SDK Manager 或者選擇 Tools > Android > SDK Manager。 點選 SDK Tools 標籤。 展開 Support Repository 並選中 Android Support Repository 複選框。 點選 OK。 繼續安裝嚮導的說明操作,安裝軟體包。
  • 將以下程式碼行新增到 build.gradle 檔案的 dependencies 塊中,向您的專案新增 support-annotations 依賴項: dependencies { compile 'com.android.support:support-annotations:24.2.0' }

如果下載的庫版本可能較高,因此,確保在此指定的值與第 3 步中的版本匹配。 在顯示的工具欄或同步通知中,點選 Sync Now。

2 執行程式碼檢查

要從 Android Studio 啟動程式碼檢查(包含驗證註解和自動 Lint 檢查),請從選單欄中選擇 Analyze > Inspect Code。Android Studio 將顯示衝突訊息,在您的程式碼與註解衝突的地方標記潛在問題並建議可能的解決方法。

3 Android常用註解

3.1 Nullness 註解

Nullness註解包括@Nullable @NonNull註解,以檢查變數引數或者返回值的nullness。@Nullness

表示可以為null;@NonNull表示不可以為null

通過@Nullable標記的方法,如果使用其返回值不進行null的檢查,則會出現警告。

@Nullable
public TextView getTextView(){
    return new TextView(this);
}
//使用
getTextView().setVisibility(View.VISIBLE);

在Android Studio中會報警告:Method invocation “setVisibility” may produce ‘java.lang.NullPointerException’…

3.1.1 Nullness 分析

Android Studio 支援通過執行 nullability分析,在您的程式碼中自動推斷和插入 nullness註解。Nullability分析會在您程式碼的整個方法層次結構中掃描協定類,以檢測:

  • 可返回 Null 的呼叫方法
  • 不會返回 Null 的方法
  • 可以為 Null 的變數,如欄位、區域性變數和引數
  • 不能為 Null 值的變數,如欄位、區域性變數和引數

然後,此分析將自動在已檢測到的位置插入相應的 null 註解。 要在 Android Studio 中執行 nullability 分析,請選擇 Analyze > Infer Nullity。Android Studio 會在程式碼中已檢測到的位置插入 Android @Nullable 和 @NonNull 註解。執行 null 分析後,最好驗證一下插入的這些註解。

3.2資源註解

驗證資源型別可能非常有用,因為Android對資源(例如可繪製物件和字串資源)的引用以整型形式傳遞。需要引數來引用特定型別資源(例如可繪製物件)的程式碼可以作為預計的引用型別 int 傳入,不過實際將引用不同型別的資源,例如 R.string 資源。 例如,新增 @StringRes 註解,以檢查資源引數是否包含 R.string 引用,如下面所示:

public abstract void setTitle(@StringRes int resId) {}

在程式碼檢查期間,如果引數中未傳入 R.string 引用,註解將生成警告。 常見的資源註解:

@IntegerRes:R.integer 型別資源。 @AnimatorRes:R.animator 型別資源。 @AnimRes:R.anim 型別資源。 @ArrayRes:R.array 型別資源。 @AttrRes:R.attr 型別資源。 @BoolRes:R.bool 型別資源。 @ColorRes:R.color 型別資源。 @DimenRes:R.dimen 型別資源。 @DrawableRes:R.drawable 型別資源。 @FractionRes:R.fraction 型別資源。(百分比) @IdRes:R.id 型別資源。 @InterpolatorRes:R.interpolator 型別資源。(插值器) @LayoutRes:R.layout 型別資源。 @MenuRes:R.menu 型別資源。 @PluralsRes:R.plurals 型別資源。(複數) @RawRes:R.raw 型別資源。 @StyleableRes:R.styleable 型別資源。 @StyleRes:R.style 型別資源。 @TransitionRes: R.transition 型別資源。 @XmlRes:R.xml 型別資源。 @AnyRes:未知資源。(表示自己不知道是什麼型別的資源。比如有可能為 R.drawable 也有可能是 R.string。)

可以使用相同的註解格式新增並在程式碼檢查期間執行。如果您的引數支援多種資源型別,您可以在給定引數上新增更多註解。 @AnyRes 能夠指示註解的引數可為任意型別的 R 資源。

@ColorRes 與@ColorInt 儘管您可以使用 @ColorRes 指定某個引數應為顏色資源,但是顏色整型(RRGGBB 或 AARRGGBB 格式)無法識別為顏色資源。請改用 @ColorInt 註解指示某個引數必須為顏色整型。構建工具會標記不正確程式碼,該程式碼會將顏色資源 ID(例如 android.R.color.black)而不是顏色整型傳遞到已註解方法。

3.3 執行緒註解

執行緒註解可以檢查某個方法是否從特定型別的執行緒呼叫。支援以下執行緒註解

  • @MainThread
  • @UiThread
  • @WorkerThread
  • @BinderThread
  • @AnyThread

注:1、構建工具會將 @MainThread 和 @UiThread 註解視為可互換,因此,您可以從 @MainThread 方法呼叫 @UiThread 方法,反之亦然。不過,如果系統應用在不同執行緒上帶有多個檢視,UI 執行緒可與主執行緒不同。因此,您應使用 @UiThread 標註與應用的檢視層次結構關聯的方法,使用 @MainThread 僅標註與應用生命週期關聯的方法。 2、WorkerThread 表示標記的方法只應該在工作執行緒上呼叫。如果標記的是一個類,那麼該類中的所有方法都應是在一個工作執行緒上呼叫 3、BinderThread 表示標記的方法只應在繫結執行緒上呼叫。如果標記的是一個類,那麼該類中的所有方法都應是在繫結執行緒被呼叫

3.4 值約束註解

使用 @IntRange、@FloatRange 和 @Size 註解可以驗證傳遞的引數的值。在應用到使用者可能弄錯其範圍的引數時,@IntRange 和 @FloatRange 都非常有用。 例:

public void setAlpha(@IntRange(from=0,to=255) int alpha) {}
public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {...}

@Size 註解可以檢查集合或陣列的大小,以及字串的長度。@Size 註解可用於驗證以下質量:

最小大小(例如 @Size(min=2)) 最大大小(例如 @Size(max=2)) 確切大小(例如 @Size(2)) 表示大小必須為此倍數的數字(例如 @Size(multiple=2))

int[] location = new int[3];
button.getLocationOnScreen(@Size(min=1) location);

3.5 許可權註解

使用 @RequiresPermission 註解可以驗證方法呼叫方的許可權。

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

@RequiresPermission(allOf = {
    Manifest.permission.READ_EXTERNAL_STORAGE,
    Manifest.permission.WRITE_EXTERNAL_STORAGE})
public static final void copyFile(String dest, String source) {
    ...
}

要檢查有效許可權列表中是否存在某個許可權,請使用 anyOf 屬性。要檢查是否存在一組許可權,請使用 allOf 屬性。上面的示例會標註 setWallpaper() 方法,以確保方法的呼叫方擁有 permission.SET_WALLPAPERS 許可權; 要求 copyFile() 方法的呼叫方同時具有外部儲存空間的讀寫許可權

對於 intent 許可權,請將許可權要求新增到定義 intent 操作名稱的字串欄位上:

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

對於您需要單獨讀寫許可權的內容提供程式的許可權,請在 @RequiresPermission.Read@RequiresPermission.Write註解中包含每個許可權要求:

@RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS))
@RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS))
public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks");

間接許可權

如果許可權依賴於提供給方法引數的特定值,請對引數本身使用 @RequiresPermission,而不用列出具體許可權。例如, startActivity(Intent) 方法會對傳遞到方法的 intent 使用間接許可權:

public abstract void startActivity(@RequiresPermission Intent intent, @Nullable Bundle) {...}

在您使用間接許可權時,構建工具將執行資料流分析以檢查傳遞到方法的引數是否具有任何 @RequiresPermission 註解。隨後,它們會對方法本身強制引數的任何現有註解。在 startActivity(Intent) 示例中,當一個不具有相應許可權的 intent 傳遞到方法時,Intent 類中的註解會針對 startActivity(Intent) 的無效使用生成警告,如圖 1 中所示。

此處輸入圖片的描述 圖 1. startActivity(Intent) 方法上從間接許可權註解生成的警告。

構建工具會在 startActivity(Intent) 上從 Intent 類中相應 intent 操作名稱的註解生成警告:

@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@RequiresPermission(Manifest.permission.CALL_PHONE)
public static final String ACTION_CALL = "android.intent.action.CALL";

如果需要,在標註方法的引數時,您可以將 @RequiresPermission 替換為 @RequiresPermission.Read 和/或 @RequiresPermission.Write。不過,間接許可權 @RequiresPermission 不應與讀取或寫入許可權註解搭配使用。

3.6 CallSuper 註解

使用 @CallSuper 註解可以驗證替換方法是否會呼叫方法的超類實現。下面的示例會標註 onCreate() 方法,以確保任何替換方法實現都會呼叫 super.onCreate():

@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}

3.7 Typedef 註解

使用 @IntDef 和 @StringDef註解,能夠建立整型和字串集的 列舉 註解來驗證其他型別的程式碼引用。 Typedef 註解可以確保特定引數、返回值或欄位引用特定的常量集。它們還可以完成程式碼以自動提供允許的常量。

下面的示例說明了建立註解的具體步驟,此註解可以確保作為方法引數傳遞的值引用一個定義的常量:

import android.support.annotation.IntDef;
...
public abstract class ActionBar {
    ...
    // Define the list of accepted constants and declare the NavigationMode annotation
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
    public @interface NavigationMode {}

    // Declare the constants
    public static final int NAVIGATION_MODE_STANDARD = 0;
    public static final int NAVIGATION_MODE_LIST = 1;
    public static final int NAVIGATION_MODE_TABS = 2;

    // Decorate the target methods with the annotation
    @NavigationMode
    public abstract int getNavigationMode();

    // Attach the annotation
    public abstract void setNavigationMode(@NavigationMode int mode);

在您構建此程式碼時,如果 mode 引數不引用一個定義的常量(NAVIGATION_MODE_STANDARD、NAVIGATION_MODE_LIST 或 NAVIGATION_MODE_TABS),則會生成警告。

您還可以組合 @IntDef 和 @IntRange,以指示整型可以是給定的常量集或某個範圍內的值。

允許將常量與標誌相結合

如果使用者可以將允許的常量與標誌(例如,|、& 和 ^,等等)相結合,則您可以通過 flag 屬性定義一個註解,以檢查某個引數或返回值是否會引用有效模式。下面的示例將使用一組有效的 DISPLAY_ 常量建立 DisplayOptions 註解:

import android.support.annotation.IntDef;
...
public static final int DISPLAY_USE_LOGO = 1;
public static final int DISPLAY_SHOW_HOME = 2;
public static final int DISPLAY_HOME_AS_UP= 4;
public static final int DISPLAY_SHOW_TITLE= 8;
public static final int DISPLAY_SHOW_CUSTOM =16;
@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 {}
//使用
@DisplayOptions int a= DISPLAY_USE_LOGO;
@DisplayOptions int b= DISPLAY_SHOW_HOME;
@DisplayOptions int c= a|b;

在您使用註解標誌構建程式碼時,如果經過修飾的引數或返回值不引用有效模式,則將生成警告。

3.8 刪除線格式 可訪問性註解

使用 @VisibleForTesting 和 @Keep 註解可以表示方法、類或欄位的可訪問性。

@VisibleForTesting 註解指示一個程式碼塊的可見性是否高於讓程式碼變得可測試所需要的水平。

@Keep 註解可以確保標記的指定程式碼在混淆時不會被混淆。它一般會新增到通過反射訪問的方法和類中,以阻止編譯器將程式碼視為未使用。

參考資料: