Android 中注解的使用

前言

Android Support Library 從 19.1 版本開始引入了一個(gè)新的注解庫陨舱,其中包含了很多的元注解搜贤,使用它們修飾我們的代碼, 可以讓我們提高程序的開發(fā)效率锯岖,讓我們更早的發(fā)現(xiàn)問題介袜。以及對(duì)代碼施以規(guī)范,讓代碼更加有可讀性出吹。這篇文章就來簡(jiǎn)單了解下這些注解遇伞,以及其使用。如有錯(cuò)誤和遺漏捶牢,歡迎留言和補(bǔ)充~

注:現(xiàn)在我們新建項(xiàng)目直接就依賴了 support.appcompat 包鸠珠,其中已經(jīng)依賴了 annotations 包加派。如果你的項(xiàng)目中寫如下注解報(bào)錯(cuò),可以添加注解包:

dependencies {
    compile 'com.android.support:support-annotations:22.2.0'
}

@IntDef & @StringDef

替代 Java 中枚舉的注解跳芳,以 @IntDef 為例芍锦,定義和使用如下:

@IntDef({RED, BLUE, YELLOW})
@Retention(RetentionPolicy.SOURCE)
public @interface LightColors{};

public static final int RED = 1;
public static final int BLUE = 2;
public static final int YELLOW = 3;

public void setColor(@LightColors int color){
}
  • @interface:聲明新的枚舉注解類型。
  • @Retention(RetentionPolicy.SOURCE):告知編譯器不將枚舉的注解數(shù)據(jù)存儲(chǔ)在 .class 文件中飞盆。

如果允許常量與標(biāo)志(例如:|娄琉、& 和 ^ 等等)相結(jié)合,則我們可以使用 flag 屬性吓歇,如:

@IntDef(flag = true, value = {RED, BLUE, YELLOW})

使用:

setColor(RED | BLUE);

@Nullable & @NonNull

  • @Nullable:注解的元素可以為 null孽水。
  • @NonNull:注解的元素不可以為 null。

上面的注解可以修飾如下元素:
1城看,方法參數(shù)女气。如:

@Nullable
private String data;

2,方法的返回值测柠。 如:

@Nullable
public String getData(){
    return data;
}

3炼鞠,成員屬性。如:

public void setData(@Nullable String data){
}

當(dāng)用空的參數(shù)傳給被 @NonNull 修飾的方法參數(shù)的方法時(shí)轰胁,會(huì)給出如下警告提示(編譯不會(huì)報(bào)錯(cuò)):

passing "null" argument to parameter annotated as @NotNull

@FloatRange & @IntRange

@FloatRange 和 @IntRange 是用于限定范圍的注解谒主。其中 @FloatRange 是限定 float 類型的,而 @IntRange 是限定 int 類型的赃阀。它們同上注解一樣霎肯,可以修飾方法參數(shù)、方法返回值榛斯、成員屬性观游。

以 @IntRange 為例,修飾方法參數(shù)的定義如下:

public void setAge(@IntRange(from = 1, to = 180) int age){
}

如果調(diào)用該方法傳的參數(shù)不在 1 - 180 的范圍內(nèi)驮俗, 如:setAge(0)懂缕,那么編譯會(huì)直接報(bào)如下錯(cuò):

value must be ≥ 1 and ≤ 180 (was 0)

@Size

@Size 注解的作用是限定長(zhǎng)度的,同上注解一樣意述,可以修飾方法參數(shù)提佣、方法返回值、成員屬性荤崇。

  • 限定字符串的長(zhǎng)度:
public void setData(@Size(4) String data){
}

當(dāng)傳入的字符串長(zhǎng)度不等于 4 時(shí),編譯器會(huì)直接報(bào)錯(cuò):

Length must be exactly 4 
  • 限定數(shù)組的長(zhǎng)度:
public void setData(@Size(4) int[] data){
}
  • 特殊的限定潮针,如限定為 2 的倍數(shù):
public void setData(@Size(multiple = 2) int[] data){
}

限定最小的長(zhǎng)度:

@Size(min = 2)

限定最大的長(zhǎng)度:

@Size(max = 2)

等同于 @Size(2) 寫法:

@Size(value = 2)

@RequiresPermission

該注解作用是表明方法所執(zhí)行的內(nèi)容需要權(quán)限术荤。如需要單個(gè)權(quán)限:

@RequiresPermission(Manifest.permission.CALL_PHONE)
private void callPhone(String phone){
}

需要一組權(quán)限:

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

對(duì)于 intent 權(quán)限,我們可以定義在 intent 操作名稱的字符串上:


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

對(duì)于需要單獨(dú)讀寫權(quán)限的內(nèi)容提供程序的權(quán)限每篷,我們可以在 @RequiresPermission.Read 或 @RequiresPermission.Write 注解中包含每個(gè)權(quán)限要求:

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

如果權(quán)限依賴于提供給方法參數(shù)的特定值瓣戚,那么可以對(duì)參數(shù)本身使用 @RequiresPermission 而不用列出具體的權(quán)限端圈,如 startActivity(intent) 方法:

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

當(dāng)我們使用這種方式(間接權(quán)限)時(shí),構(gòu)建工具將執(zhí)行數(shù)據(jù)流分析以檢查傳遞到方法的參數(shù)是否具有任何 @RequiresPermission 注解子库。如:

Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:1234567890"));
startActivity(intent);

這里的 startActivity(intent) 就直接報(bào)錯(cuò)了:

call requires permission which may be rejected by user: code should explicitly check to see if permission is available (with `checkPermission`) or explicitly handle a potential `SecurityException`

因?yàn)? Intent.ACTION_CALL 中標(biāo)記了權(quán)限注解:

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

@CheckResult

@CheckResult 注解是作用于方法上的舱权,作用是檢驗(yàn)有沒有處理返回值。如果沒有處理返回值則會(huì)報(bào)錯(cuò)仑嗅。

@CheckResult
public String getData(String data) {
    return data.trim();
}

線程注解

線程注解可以檢查某個(gè)方法是否從特定類型的線程調(diào)用宴倍。支持以下線程注解:

  • @MainThread:表示標(biāo)記的方法只應(yīng)在主線程調(diào)用。如果標(biāo)記的是一個(gè)類仓技,那么該類中的所有方法都應(yīng)該是在主線程被調(diào)用鸵贬。例:(通常,應(yīng)用程序的主線程也是 Ui 線程脖捻。但是阔逼,在特殊情況下,應(yīng)用程序的主線程可能不是其 Ui 線程)
@MainThread
public void deliverResult(D data) { ... }
  • @UiThread:表示標(biāo)記的方法或構(gòu)造函數(shù)只應(yīng)該在 Ui 線程上調(diào)用地沮。如果標(biāo)記的是一個(gè)類嗜浮,那么該類中的所有方法都應(yīng)是在 Ui 線程被調(diào)用。例:
@UiThread
public abstract void setText(@NonNull String text) {...}
  • @WorkerThread:表示標(biāo)記的方法只應(yīng)該在工作線程上調(diào)用摩疑。如果標(biāo)記的是一個(gè)類周伦,那么該類中的所有方法都應(yīng)是在一個(gè)工作線程上調(diào)用。例:
@WorkerThread
protected abstract FilterResults performFiltering(CharSequence constraint);
  • @BinderThread:表示標(biāo)記的方法只應(yīng)在綁定線程上調(diào)用未荒。如果標(biāo)記的是一個(gè)類专挪,那么該類中的所有方法都應(yīng)是在綁定線程被調(diào)用。例:
@BinderThread
public BeamShareData createBeamShareData() { ... }
  • @AnyThread:表示可以從任何線程調(diào)用帶標(biāo)記的方法片排。如果標(biāo)記的是一個(gè)類寨腔,那么該類中的所有方法都可以從任何線程中調(diào)用。例:
@AnyThread
public void deliverResult(D data) { ... }

構(gòu)建工具會(huì)將 @MainThread 和 @UiThread 注解視為可以互換率寡,因此迫卢,我們可以從 @MainThread 方法調(diào)用 @UiThread 方法,反之亦然冶共。不過如果系統(tǒng)應(yīng)用在不同線程上帶有多個(gè)試圖乾蛤,Ui 線程可與主線程不同。因此捅僵,我們應(yīng)該使用 @UiThread 標(biāo)注于應(yīng)用的視圖層次結(jié)構(gòu)關(guān)聯(lián)的方法家卖,使用 @MainThread 僅標(biāo)注于應(yīng)用生命周期關(guān)聯(lián)的方法。

資源注解

在 Android 中幾乎所有的資源都有其對(duì)于的 id庙楚,我們?cè)谑褂玫臅r(shí)候可以直接通過 id 來上荡,如:

textView.setText(getResources().getText(R.string.app_name));

但是這樣如果沒有寫指定的資源注解的話就會(huì)風(fēng)險(xiǎn),比如隨便傳了個(gè) 0馒闷,那么就會(huì)找不到對(duì)應(yīng)的資源酪捡。
為了避免由于自己的粗心大意而引發(fā)的錯(cuò)誤叁征,我們就可以使用資源注解了,如:

public int getText(@StringRes int id){
}

這樣當(dāng)我們調(diào)用該方法時(shí)逛薇,如果傳遞的參數(shù)并不是 String 類型的資源 id捺疼,那么編譯器就會(huì)報(bào)錯(cuò)提示。

除了 @StringRes 資源注解外永罚,還有:

  • @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 類型資源挟炬。(復(fù)數(shù))
  • @RawRes:R.raw 類型資源鸥滨。
  • @StyleableRes:R.styleable 類型資源。
  • @StyleRes:R.style 類型資源谤祖。
  • @TransitionRes: R.transition 類型資源婿滓。
  • @XmlRes:R.xml 類型資源。
  • @AnyRes:未知資源粥喜。(表示自己不知道是什么類型的資源凸主。比如有可能為 R.drawable 也有可能是 R.string。)

@ColorInt

@ColorInt 注解的作用為:限定顏色值额湘。(ARGB:0xAARRGGBB)

public void setColor(@ColorInt int color) {

}

如果直接使用資源 id卿吐,則會(huì)報(bào)錯(cuò),如下:

setColor(R.color.colorAccent)// 報(bào)錯(cuò)

正確的使用是:

setColor(0xFFFF00FF);

如果要使用資源 id锋华,則可以通過 ContextCompat.getColor() 方法來:

setColor(ContextCompat.getColor(context, R.color.colorAccent));

@CallSuper

該注解用于修飾方法嗡官,表示重寫該方法時(shí)必須調(diào)用 super 方法。如 onCreate() 方法:

@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}

重寫 onCreate() 方法時(shí)供置,必須調(diào)用 super 方法:

super.onCreate(savedInstanceState);

否則報(bào)錯(cuò)谨湘。

@VisibleForTesting & @Keep

使用 @VisibleForTesting 和 @Keep 注解可以表示方法、類芥丧、或字段的可訪問性紧阔。

  • @VisibleForTesting:該注解只起到一個(gè)注釋的作用,告訴其他開發(fā)者被標(biāo)記的代碼為什么有這么大的可見程度(為了測(cè)試方便)续担。因此擅耽,經(jīng)常用來修飾 public 或 protected,用來修飾 private 并不會(huì)報(bào)錯(cuò)物遇,但是沒有意義乖仇。

  • @Keep:標(biāo)記的指定代碼在混淆時(shí)不會(huì)被混淆。

參考:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末询兴,一起剝皮案震驚了整個(gè)濱河市乃沙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌诗舰,老刑警劉巖警儒,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異眶根,居然都是意外死亡蜀铲,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門属百,熙熙樓的掌柜王于貴愁眉苦臉地迎上來记劝,“玉大人,你說我怎么就攤上這事族扰⊙岢螅” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵渔呵,是天一觀的道長(zhǎng)怒竿。 經(jīng)常有香客問我,道長(zhǎng)厘肮,這世上最難降的妖魔是什么愧口? 我笑而不...
    開封第一講書人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮类茂,結(jié)果婚禮上耍属,老公的妹妹穿的比我還像新娘。我一直安慰自己巩检,他們只是感情好厚骗,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著兢哭,像睡著了一般领舰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,215評(píng)論 1 299
  • 那天冲秽,我揣著相機(jī)與錄音舍咖,去河邊找鬼。 笑死锉桑,一個(gè)胖子當(dāng)著我的面吹牛排霉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播民轴,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼攻柠,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了后裸?” 一聲冷哼從身側(cè)響起瑰钮,我...
    開封第一講書人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎微驶,沒想到半個(gè)月后浪谴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡祈搜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年较店,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片容燕。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡梁呈,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蘸秘,到底是詐尸還是另有隱情官卡,我是刑警寧澤,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布醋虏,位于F島的核電站寻咒,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏颈嚼。R本人自食惡果不足惜毛秘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望阻课。 院中可真熱鬧叫挟,春花似錦、人聲如沸限煞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽署驻。三九已至奋献,卻和暖如春健霹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瓶蚂。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工糖埋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人扬跋。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓阶捆,卻偏偏與公主長(zhǎng)得像凌节,于是被迫代替她去往敵國(guó)和親钦听。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,083評(píng)論 25 707
  • 什么是注解 注解對(duì)于開發(fā)人員來講既熟悉又陌生倍奢,熟悉是因?yàn)橹灰闶亲鲩_發(fā)朴上,都會(huì)用到注解(常見的@Override);...
    張明云閱讀 25,159評(píng)論 6 154
  • Default Parameters(默認(rèn)參數(shù)) in ES6 Template Literals (模板文本)i...
    Otherthing閱讀 179評(píng)論 0 0
  • 昨晚八點(diǎn)下著雨卒煞,從帳蓬里冒雨伸出來隨手一拍痪宰,多美的天空啊畔裕! 雨從昨天一直下到今天衣撬,早上七點(diǎn)多鐵路保安又來叫我離開。...
    環(huán)華小蝸牛閱讀 213評(píng)論 0 1
  • 一杯溫開水扮饶,半本胡雪巖具练,偷得浮生半日閑,忘卻窗外是何年甜无。數(shù)篇短文章扛点,百轉(zhuǎn)冷熱腸,為誰辛苦為誰忙岂丘?昨日因陵究,今日果,且...
    自由和安閱讀 373評(píng)論 2 1