Android進階Support Annotation Library 使用詳解

Support Annotation Library是從Android Support Library 19.1 開始引入的一個全新的函數包,它包含一系列有用的元註解,用來幫助開發者在編譯期間發現可能存在的Bug。Support Library自己也使用Annotation Library 提供的註解來完善自身的代碼質量,android Studio 提供可視化的交互以便開發者發現問題。html

Android Support Library 發展到如今已經不止是一個jar包了,而是拆分紅多個獨立的Jar包,例如support-v四、support-v七、gridlayout-v七、design、cardview-v7等等。而Annotation Libary 也是其中之一,默認狀況下是不會包含在工程中的,若是咱們的SDK已經安裝了android Support Repository,那麼咱們打開Project Structure 對話框,並選中一個Module,選中Dependencies選項,點擊「+」按鈕,在彈出的Choose Library Dependency 對話框中輕鬆找到Annotation Library。java

這裏寫圖片描述

點擊添加後,在Module的build.gradle文件中會新增長Annotation函數庫的依賴以下:android

compile 'com.android.support:support-annotations:26.0.0-alpha1'
  • 下面咱們按照類型進行一一介紹。

1. Nullness 註解

此類型包含以下內容:數組

  • @Nullable做用於函數參數或返回值,標記參數或返回值能夠爲空。
  • @NonNull做用於函數參數或返回值,標記參數或返回值不能爲爲空。

若是在函數參數或返回值使用了上述註解,而又出現違反該註解的代碼時,Android Studio 會給出提示,同時使用Android Lint進行靜態代碼掃描,也會顯示出錯提示。ide

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        test(null);
    }
    private void test(@NonNull String str) {
        Log.e(TAG,str);
    }
  • 咱們用Android Lint掃描這個文件的話,在掃描結果中會出現以下錯誤:

這裏寫圖片描述

2. 資源類型註解

咱們知道,資源是以int整型表示,並保存在R.Java文件中。這就意味着在一個須要Layout資源值函數傳入String字符串,在編譯時不會報錯,只有在運行時纔會報錯,爲了防止這種狀況的出現,可使用資源類型註解。函數

資源類型的註解做用於函數參數、返回值及類的變量,每種資源類型對應一種註解。測試

  • AnimatorRes:標記整型值是android.R.animation類型。gradle

  • AnimRes:標記整型是android.R.anim類型。ui

  • AnyRes:標記整型是任何一種資源類型,若是確切知道表示的是哪個具體資源的話,建議顯式指定。this

  • ArrayRes:標記整型是android.R.array類型。

  • AttrRes:標記整型是android.R.attr類型。

  • BoolRes:標記整型是布爾類型。

  • ColorRes:標記整型是android.R.color類型。

  • DrawableRes:標記整型是android.R.drawable類型。

  • FranctionRes:標記整型值是fraction類型,這個比較少見,這種類型資源常見於Animation 
    Xml中,好比50%,表示佔parent的50%

  • IdRes:標記整型是android.R.id類型。

  • IntegerRes:標記整型是android.R.integer類型。

  • InterpolatorRes:標記整型是android.R.interpolator類型,插值器,在Animation 
    Xml中使用較多。

  • LayoutRes:標記整型是android.R.layout類型。

  • MenuRes:標記整型是android.R.menu類型。

  • RawRes:標記整型是android.R.raw類型。

  • StringRes:標記整型是android.R.string類型。

  • StyleableRes:標記整型是android.R.styleable類型。

  • StyleRes:標記整型是android.R.style類型。

  • XmlRes:標記整型是android.R.xml類型。

看一下例子。這裏傳入字符串如果不加@LayoutRes,是不會報錯,

如果加了就會報錯。提早知道錯誤在哪。這樣就會少不少麻煩。舉個例子,在AppCompatAcitivity的setContentView函數使用@LayoutRes標記它的參數。

@Override
    public void setContentView(@LayoutRes int layoutResID) {
        getDelegate().setContentView(layoutResID);
    }
  •  

3. 類型定義註解

在Android開發中,整型值不止常常用來表明資源引用值,並且常常用來代替枚舉值。@IntDef註解用來建立一個整型類型定義的新註解,咱們可使用這個新註解來標記本身編譯的API。先看看@IntDef的源碼。

@Retention(SOURCE)  
@Target({ANNOTATION_TYPE})  
public @interface IntDef {  
    /** Defines the allowed constants for this element */  
    long[] value() default {};  

    /** Defines whether the constants can be used as a flag, or just as an enum (the default) */  
    boolean flag() default false;  
}
  • 這裏面能夠定義一個布爾值,還能夠定義多個long類型的值。那麼就以long數組舉例。
public abstract class AnnotationTest {  
    public static final int TEST_1 = 0;  
    public static final int TEST_2 = 1;  
    public static final int TEST_3 = 2;  
    @Retention(RetentionPolicy.SOURCE)  
    @IntDef({TEST_1,TEST_2,TEST_3})  
    public @interface TestAnnotation{}  

    @TestAnnotation  
    public abstract int getTestAnnotation();  

    public abstract void setTestAnnotation(@TestAnnotation int testAnnotation);  
}
  • 這裏給TestAnnotation註解加上了@IntDef,這樣在使用TestAnnotation的時候必須傳入指定參數,如果非法在編譯時就會報異常。

使用就很是簡單了,找個類繼承抽象類,實現方法。在調用的時候,只能傳入指定的TEST_1,TEST_2,TEST_3。

這樣就能夠自定義資源類型註解,很是方便。

4. 線程註解

Android應用開發過程當中,常常會涉及到多種線程的使用,界面相關操做必須在主線程,而耗時操做如文件下載等必須在後臺線程中,

線程註解相關有四種。

  • @UiThread:標記運行在UI線程,一個應用只有一個UI線程,多數是用於View的標註。(這裏先前有錯誤,感謝樓下評論朋友提醒)

  • @MainThread:標記運行在主線程,一個應用只有一個主線程,主線程也是@UiThread線程。一般狀況下,咱們使用@MainThread

來註解生命週期相關函數,使用@UiThread來註解視圖相關函數,通常狀況下@MianThread和@UiThraed是能夠互換的。

  • @WorkerThread:標記運行在後臺運行線程。

  • @BinderThread:標記運行在Binder線程。

一個典型的例子就是AsyncTask的源碼,咱們截取部分代碼以下。

@MainThread
    protected void onPreExecute() {
    }
    @MainThread
    protected void onPostExecute(Result result) {
    }
    @MainThread
    protected void onProgressUpdate(Progress... values) {
    }
  •  

5. RGB顏色值註解

在資源類型註解中咱們使用@ColorRes來標記參數類型須要傳入顏色類型的id,而使用@ColorInt註解是標記參數類型須要傳入RGB或者ARGB顏色值的整型值,在TextView的源碼中能夠找到@ColorInt的例子。

@android.view.RemotableViewMethod
public void setTextColor(@ColorInt int color) {
        mTextColor = ColorStateList.valueOf(color);
        updateTextColors();
    }
  •  

6. 值範圍註解

當函數參數的取值在必定範圍時,可使用註解來防止調用者傳入錯誤的參數,主要註解有三種註解。

  • @Size:對於相似數組、集合和字符串之類的參數,咱們可使用@Size註解來表示這些參數的大小。用法:

    • @Size(min=1)//能夠表示集合不能夠爲空

    • @Size(max=23)//能夠表示字符串最大字符個數爲23

    • @Size(2)//表示數組元素個數爲2個

    • @Size(multiple=2)//能夠表示數組大小是2的倍數

  • @IntRange:參數類型是int或者long,用法以下

public void setAlpha(@IntRange(from=0,to=255) int alpha){...}
  • @FloatRange:參數類型是float或者double,用法以下。
public void setAlpha(@FloatRange(from=0.0,to=1.0) float alpha){...}
  •  

7. 權限註解

Android應用在使用某些系統功能時,須要在AndroidManifest,xml中聲明權限,不然在運行時就會提示缺失對應的權限,爲了在編譯時及時發現權限的缺失,咱們可使用@RequiresPermission註解。

  • 若是函數調用須要聲明一個權限,語句以下:
@RequiresPermission(Manifest.permission.SET_WALLPAPER)
public abstract void setWallpaper(Bitmap bitmap) throws IOException;
  • 若是須要一個集合至少一個權限,語句以下:
@RequiresPermission(anyOf= {
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION})
public abstract Location getLastKnownLocation(String Provider);
  • 若是同時須要多個權限,語句以下。
@RequiresPermission(allOf = {
Manifest.permission.READ_HISTORY_BOOKMARKS,
Manifest.permission.WRITE_HISTORY_BOOKMARKS})
public static final void updateVisitedHistory(ContentResolver cr,String url,boolean real);
  • 對於Intent調用所需權限,能夠在Intent的ACTION字符串定義處添加註解。語句以下:
@RequiresPermission(android.Manifest.permission.BLUETOOTH)
public static final String ACTION_REQUEST_DISCOVERRAVLE = "android.bluetooth.adapter.REQUEST_DISCOVERRAVLE";
  • 對於ContentProvider所需權限,可能有讀和寫兩個操做。對應不一樣的權限。
@RequiresPermission.Read(@RequestPermission(READ_HISTORY_BOOLMARKS))
@RequiresPermission.Write(@RequestPermission(WRITE_HISTORY_BOOLMARKS))
public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks");
  •  

8. 重寫函數註解

若是API容許重寫某個函數,可是要求在重寫該函數時須要調用super父類的函數,不然代碼邏輯可能會出錯,那麼能夠加註解@CallSuper來提示開發者。

@CallSuper
protected void onCreate(@Nullable Bundle saveInstanceState);
  •  

9. 返回值註解

若是咱們編寫的函數須要調用對返回值作某種處理,那麼可使用@CheckResult註解來提示開發者。固然咱們沒有必要對每一個非空返回值的函數都添加這個註解,該註解的主要目的是讓調用者在使用API時不至於懷疑該函數是否會產生反作用。看下Context類中checkPermission中的源碼:

@CheckResult(suggest="#enforcePermission(String,int,int,String)")
    @PackageManager.PermissionResult
    public abstract int checkPermission(@NonNull String permission, int pid, int uid);

    @CheckResult(suggest="#enforceCallingPermission(String,String)")
    @PackageManager.PermissionResult
    public abstract int checkCallingPermission(@NonNull String permission);
  •  

若是調用者沒有檢查這兩個函數的返回值,那麼就會警告,警告信息中包含suggest屬性中的內容。

10. @VisibleForTesting註解

單元測試中可能須要訪問到一些不可見的類、函數或者變量,這時可使用@VisibleForTesting註解來使其對測試可見。

11. @Keep註解

@keep是用來標記在Proguard混淆過程當中不須要混淆的類或者方法。在混淆時一些不須要混淆的會使用

-keep class com.foo.bar{public static method>}
  • 有了@Keep以後,就能夠在編碼時標註出一些不須要混淆的類或者方法
public class AnnotationDemo {
    @Keep
    public void doSomething(){
    // ...
    }
// ...
}
  •  

12. @SuppressWarnings忽略警告

java.lang.SuppressWarnings是J2SE 5.0中標準的Annotation之一。能夠標註在類、字段、方法、參數、構造方法,以及局部變量上。做用:告訴編譯器忽略指定的警告,不用在編譯完成後出現警告信息。

注意:SuppressWarnings是java.lang包下的,以前說的都是android.support.annotation包下的

使用:

  • @SuppressWarnings(「」)
  • @SuppressWarnings({})
  • @SuppressWarnings(value={})

示例:

  • @SuppressWarnings(「unchecked」)

    告訴編譯器忽略 unchecked 警告信息,如使用List,ArrayList等未進行參數化產生的警告信息。

  • @SuppressWarnings(「serial」)

    若是編譯器出現這樣的警告信息:The serializable class WmailCalendar does not declare a static final serialVersionUID field of type long

    使用這個註釋將警告信息去掉。

  • @SuppressWarnings(「deprecation」)

    若是使用了使用@Deprecated註釋的方法,編譯器將出現警告信息。 
    使用這個註釋將警告信息去掉。

  • @SuppressWarnings(「unchecked」, 「deprecation」)

    告訴編譯器同時忽略unchecked和deprecation的警告信息。

  • @SuppressWarnings(value={「unchecked」, 「deprecation」})

    等同於@SuppressWarnings(「unchecked」, 「deprecation」)

一、抑制單類型警告

@SuppressWarnings("unchecked")
public void addItems(String item){
  @SuppressWarnings("rawtypes")
   List items = new ArrayList();
   items.add(item);
}
  •  

二、抑制多類型警告

@SuppressWarnings(value={"unchecked", "rawtypes"})
public void addItems(String item){
   List items = new ArrayList();
   items.add(item);
}
  •  

三、抑制所有警告

@SuppressWarnings("all")
public void addItems(String item){
   List items = new ArrayList();
   items.add(item);
}
  •  

註解目標   
                               
經過 @SuppressWarnings 的源碼可知,其註解目標爲類、字段、函數、函數入參、構造函數和函數的局部變量。而家建議註解應聲明在最接近警告發生的位置。

到這裏基本註解都已經說完了,最後說明一下,若是函數庫中使用Annotation Library,並使用Gradle生成aar壓縮包,那麼在編譯時Android Gradle插件會取出這些註解信息並打包在aar文件中,以便函數庫的調用者正常使用咱們的註解信息。aar文件中的annotations.zip文件就是抽取出來的註解信息。

參考: 
@SuppressWarnings忽略警告  《Android高級進階》

相關文章
相關標籤/搜索