Support Annotation Library 是從 Android Support Library 19.1 開始引入的一個全新的函數(shù)庫盼产,它包含了一系列有用的元注解源织,用來幫助開發(fā)者在編譯期間
發(fā)現(xiàn)可能存在的 Bug栖秕。
在 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 會提示錯誤:
類型定義注解
在 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 文件就是抽取出來的注解信息