預知Bug的神器——Support Annotation Library使用詳解

Support Annotation Library 是從 Android Support Library 19.1 開始引入的一個全新的函數(shù)庫盼产,它包含了一系列有用的元注解源织,用來幫助開發(fā)者在編譯期間發(fā)現(xiàn)可能存在的 Bug栖秕。

Annotation Library 默認情況下不會包含在工程中弧岳,如果我們的 SDK 已經(jīng)安裝了 Android Support Repository唬涧,那么我們可以通過打開工程的 Project Structure 對話框,并選中一個 Module宫补,選中 DependDencies 選項卡檬姥,點擊 “+" 按鈕,在彈出的 Choose library Dependency 對話框中輕松找到 Annotation Library粉怕,如圖:
image.png

在 support-annotations:28.0.0-alpha1 函數(shù)包中健民,總共包含 39 種注解,下面我們按照類型分別進行介紹斋荞。

Nullness 注解

該類型下的注解只有兩個

  • @Nullable:作用于函數(shù)參數(shù)或者返回值荞雏,標記參數(shù)或者返回值可以為 null
  • @NotNull:作用于參數(shù)或者返回值虐秦,標記參數(shù)或者返回值不可以為 null

當出現(xiàn)這種違反標記的代碼時平酿,Android Studio 會給出提示,同時使用 Android Lint 進行靜態(tài)代碼掃描悦陋,也會顯示出錯提示蜈彼。

資源類型注解

我們知道資源在 Android 中通常是以整型值表示的,并保存在 R.Java 文件中俺驶。這意味著一個需要傳入 Layout 資源值得函數(shù)幸逆,如果傳入 String 資源值不會再編譯期報錯棍辕,只有在運行時執(zhí)行到相應的代碼才能發(fā)現(xiàn)問題,則使用資源類型注解可以防止這種情況的出現(xiàn)还绘。

資源類型的注解作用于函數(shù)參數(shù)楚昭,返回值及類的變量,每種資源類型對應一個注解:

AnimatorRes:標記整型值是 android.R.animator 類型
AnimRes:標記整型值是 android.R.anim 類型
AnyRes:標記整型值是任何一種資源類型拍顷,如果確切知道是哪一種具體資源的話抚太,建議顯式指定
ArrayRes:標記整型值是 android.R.array 類型
AttrRes:標記整型值是 android.R.attr 類型
BoolRes:標記整型值是布爾類型
ColorRes:標記整型值是 android.R.color 類型
DrawableRes:標記整型值是 android.R.drawable 類型
FractionRes:標記整型值是 fraction 類型,這個比較少見昔案,這種類型的資源常見于 Animation Xml 中尿贫,比如 50%p,表示占 parent 的 50%
IdRes:標記整型值是 android.R.id 類型
IntegerRes:標記整型是 android.R.inter 類型
InterpolatorRes:標記整型值是 android.R.interpoloator 類型
LayoutRes:標記整型值是 android.R.layout 類型
MenuRes:標記整型值是 android.R.menu 類型
PluralsRes:標記整型值是 android.R.plurals 類型
RawRes:標記整型值是 android.R.raw 類型
StringRes:標記整型值是 android.R.string 類型
StyleableRes:標記整型值是 android.R.styleable 類型
StyleRes:標記整型值是 android.R.style 類型
TransitionRes:標記整型值是 android.R.transition 類型
XmlRes:標記整型值是 android.R.xml 類型

來看一個例子踏揣,就比如我們的 AppCompatActivity的setContentView 函數(shù)就是使用了 LayoutRes 注解表示它的參數(shù):

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

使用 LayoutRes 注解標記后庆亡,如果我們在函數(shù)中調(diào)用 setContentView 函數(shù)時傳入的參數(shù)不是 R.layout 類型,而是其他資源類型(例如 R.id 類型)那么 Android Studio 會提示錯誤:

image.png

類型定義注解

在 Android 開發(fā)中捞稿,整型值不只經(jīng)常用來代表資源引用值又谋,而且經(jīng)常用來代替枚舉值,@IntDef 注解用來創(chuàng)建一個整型類型定義的新注解括享,我們可以使用這個心注解來標記自己編寫的 API搂根,而 @IntDef 在我們常用的 ActionBar 這個類中就可以找到具體的使用方式:

public abstract class ActionBar {
//定義可以接收的常量列表
@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
//定義 NavigationMode 注解
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);
......

在使用 setNavigationMode 這個 API 時,如果傳入的參數(shù) mode 不是三個常量值之一铃辖,那么 Android Studio 就會給出警告剩愧。

線程注解

Android 應用開發(fā)過程中,經(jīng)常會涉及多線程的使用娇斩,界面相關操作必須在主線程仁卷,而耗時操作例如文件下載等則需要放到后臺線程中,線程相關注解有四種犬第。

  • @UiThread:標記運行在 UI 線程锦积,一個 UI 線程是 Activity 運行所在的主窗口,對于一個應用而言歉嗓,可能粗才能在多個 UI 線程丰介,每個 UI 線程對應不同的主窗口。
  • @MainThread:標記運行在主線程鉴分,一個應用只有一個主線程哮幢,主線程也是 @UIThread 線程,通常情況下志珍,我們使用 @MainThread 來注釋申明周期相關函數(shù)橙垢,使用 @UIThread 來注解視圖相關函數(shù),一般情況下伦糯,@MainThread 和 @UIThread 是可互換使用的柜某。
  • @WorkerThread:標記運行在后臺線程
  • @BinderThread:標記運行在 Binder 線程

一個典型的例子是 AsyncTask 的實現(xiàn)嗽元,我們看下內(nèi)部實現(xiàn):

@MainThread
protected void onPreExecute(){}
@WorkerThread
protected abstract Result doInBackground(Params ... params){};
@MainThread
protected void onProgressUpdate(Progress ... values){};

RGB顏色值注解

在資源類型中使用 @ColorRes 來標記參數(shù)類型需要傳入顏色類型的資源 id,@ColorInt 注解則是標記參數(shù)類型需要傳入 RGB 或者 ARGB 顏色整型值喂击。在 TextView 的源碼中可以找到使用 @Color 的例子剂癌。

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

值范圍注解

當函數(shù)的取值范圍在一定范圍內(nèi)時,可以使用值范圍注解來防止調(diào)用者傳入錯誤的參數(shù)翰绊,這種類型主要有三種注解

  • @Size:對于類似數(shù)組珍手、集合和字符串之類的參數(shù),我們可以使用 @Size 注解來標識這些參數(shù)的大小辞做,用法如下:
    -- @Size(min=1):表示集合不可以為空
    --@Size(max=23):表示字符串最大字符個數(shù)是 23
    --@Size(2):表示數(shù)組元素個數(shù)是 2 個
    --@Size(multiple=2):表示數(shù)組的大小必須是 2 的倍數(shù)
  • @IntRange:表示參數(shù)類型是 int 或者 long
 public void setAlpha(@IntRange(from=0,to=255) int alpha) {...}
  • @FloatRange:表示參數(shù)類型是 float 或者 double
 public void setAlpha(@FloatRange(from=0.0,to=1.0) int alpha) {...}

權限注解

Android 應用在使用某些系統(tǒng)功能是琳要,需要在 AndroidManifest.xml 中申明權限,否則在運行時會提示缺失對應的權限秤茅。為了在編譯器及時發(fā)現(xiàn)缺失的權限稚补,我們可以使用 @RequiresPermission 注解

  • 如果函數(shù)調(diào)用需要聲明一個權限,語句如下:
@ RequiresPermission(Manifest.permission.SET.WALLPAPER)
public abstract void setWallpaper(Bitmap bitmap) throws IOException;
  • 如果函數(shù)調(diào)用需要聲明集合中最少一個權限框喳,語句如下:
@ RequiresPermission(anyof = {
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS.FINE_LOCATION})
public abstract void setWallpaper(Bitmap bitmap) throws IOException;

重寫函數(shù)注解

如果 API 運行調(diào)用者重寫某個函數(shù)课幕,但同時要求重寫的函數(shù)需要調(diào)用被重寫的函數(shù),否則代碼邏輯可能會錯誤五垮,那么可以使用 @CallSuper 注解來進行提示乍惊,語句如下:

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

返回值注解

如果我們編寫的函數(shù)需要調(diào)用者對返回值做某些處理,那么可以使用@CheckResult 注解來進行提示放仗。當然我們沒有必要對每個非空返回值的函數(shù)都添加這個注解润绎,該注解的主要目的是讓調(diào)用者在使用 API 時不至于懷疑該函數(shù)是否會產(chǎn)生副作用。在 Android 源碼中诞挨,Context 類的 checkPremission 函數(shù)使用了該注解(自行查看吧)

@VisibleForTesting

單元測試中可能需要訪問到一些不可見的類莉撇、函數(shù)或者變量,這時可以使用 @VisibleForTesting 注解來使其對測試可見

@Keep

@Keep 注解用來標記在 Proguard 混淆過程中不需要混淆的類或者方法惶傻。如果你曾經(jīng)在編寫混淆文件時使用過棍郎,那么 @Keep 的用法很簡單

- keep class com.foo.bar {public static <methods> }

如果有了 @Keep 注解,則可以在代碼編寫過程中對不需要混淆的類或者方法直接標記即可

public class AnnotaionDemo{
  @Keep
  public void doSomething(){
    .....
  }
  ......
}

最后說明一下银室,如果函數(shù)庫中使用 Annotation Library涂佃,并使用 Gradle 生成 aar 壓縮包,那么在編譯時 Android Gradle 插件會抽出這些注解信息并打包在 aar 文件中蜈敢,以便函數(shù)庫的調(diào)用者正常使用我們的注解信息辜荠。aar 文件中的 annotation.zip 文件就是抽取出來的注解信息

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市扶认,隨后出現(xiàn)的幾起案子侨拦,更是在濱河造成了極大的恐慌殊橙,老刑警劉巖辐宾,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狱从,死亡現(xiàn)場離奇詭異,居然都是意外死亡叠纹,警方通過查閱死者的電腦和手機季研,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來誉察,“玉大人与涡,你說我怎么就攤上這事〕制” “怎么了驼卖?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鸿秆。 經(jīng)常有香客問我酌畜,道長,這世上最難降的妖魔是什么卿叽? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任桥胞,我火速辦了婚禮,結(jié)果婚禮上考婴,老公的妹妹穿的比我還像新娘贩虾。我一直安慰自己,他們只是感情好沥阱,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布缎罢。 她就那樣靜靜地躺著,像睡著了一般考杉。 火紅的嫁衣襯著肌膚如雪屁使。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天奔则,我揣著相機與錄音蛮寂,去河邊找鬼。 笑死易茬,一個胖子當著我的面吹牛酬蹋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抽莱,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼范抓,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了食铐?” 一聲冷哼從身側(cè)響起匕垫,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎虐呻,沒想到半個月后象泵,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寞秃,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年偶惠,在試婚紗的時候發(fā)現(xiàn)自己被綠了春寿。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡忽孽,死狀恐怖绑改,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情兄一,我是刑警寧澤厘线,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站出革,受9級特大地震影響皆的,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蹋盆,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一费薄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧栖雾,春花似錦楞抡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至账胧,卻和暖如春竞慢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背治泥。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工筹煮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人居夹。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓败潦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親准脂。 傳聞我的和親對象是個殘疾皇子劫扒,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容