探究Android中的註解

Android Support Library(安卓註解庫) 從 19.1 版本開始引入了一個新的註解庫,其中包含了很多的元註解,使用它們修飾我們的代碼, 可以讓我們提高程序的開發效率,讓我們更早的發現問題。以及對代碼施以規範,讓代碼更加有可讀性。這篇文章就來簡單瞭解下這些註解,以及其使用。如有錯誤和遺漏,歡迎留言和補充~

注:現在我們新建項目直接就依賴了 support.appcompat 包,其中已經依賴了 annotations 包。如果你的項目中寫如下註解報錯,可以添加註解包:

dependencies{ 

compile'com.android.support:support-annotations:22.2.0'

@IntDef & @StringDef

替代 Java 中枚舉的註解,以 @IntDef 爲例,定義和使用如下:

@IntDef({RED, BLUE, YELLOW}) 

@Retention(RetentionPolicy.SOURCE) 

public@interfaceLightColors{}; 

publicstaticfinalintRED = 1; 

publicstaticfinalintBLUE = 2; 

publicstaticfinalintYELLOW = 3; 

publicvoidsetColor(@LightColors intcolor){ 

  • @interface:聲明新的枚舉註解類型。
  • @Retention(RetentionPolicy.SOURCE):告知編譯器不將枚舉的註解數據存儲在 .class 文件中。

如果允許常量與標誌(例如:|、& 和 ^ 等等)相結合,則我們可以使用 flag 屬性,如:

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

使用:

setColor(RED | BLUE); 

@Nullable & @NonNull

@Nullable:註解的元素可以爲 null。

@NonNull:註解的元素不可以爲 null。

上面的註解可以修飾如下元素:

  • 1,方法參數。如:

@Nullable

private String data;

  • 2,方法的返回值。 如:

@Nullable

public String getData(){

return data;

}

  • 3,成員屬性。如:

public void setData(@Nullable String data){

}

當用空的參數傳給被 @NonNull 修飾的方法參數的方法時,會給出如下警告提示(編譯不會報錯):

passing "null"argument to parameter annotated as@NotNull 

@FloatRange & @IntRange

@FloatRange 和 @IntRange 是用於限定範圍的註解。其中 @FloatRange 是限定 float 類型的,而 @IntRange 是限定 int 類型的。它們同上註解一樣,可以修飾方法參數、方法返回值、成員屬性。

以 @IntRange 爲例,修飾方法參數的定義如下:

publicvoidsetAge(@IntRange(from= 1, to = 180) intage){ 

如果調用該方法傳的參數不在 1 - 180 的範圍內, 如:setAge(0),那麼編譯會直接報如下錯:

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

@Size

@Size 註解的作用是限定長度的,同上註解一樣,可以修飾方法參數、方法返回值、成員屬性。

限定字符串的長度:

publicvoid setData( @Size(4)String data){ 

當傳入的字符串長度不等於 4 時,編譯器會直接報錯:

Lengthmust be exactly 4

限定數組的長度:

publicvoidsetData(@Size(4) int[] data){ 

特殊的限定,如限定爲 2 的倍數:

publicvoidsetData(@Size(multiple = 2) int[] data){ 

限定最小的長度:

@ Size( min= 2) 

限定最大的長度:

@ Size( max= 2) 

等同於 @Size(2) 寫法:

@ Size( value= 2) 

@RequiresPermission

該註解作用是表明方法所執行的內容需要權限。如需要單個權限:

@ RequiresPermission( Manifest. permission. CALL_PHONE) 

private void callPhone(String phone){ 

需要一組權限:

@RequiresPermission(allOf = { 

Manifest.permission.READ_EXTERNAL_STORAGE, 

Manifest.permission.WRITE_EXTERNAL_STORAGE}) 

publicstaticfinalvoidcopyFile(String dest, String source){ 

... 

對於 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)) 

publicstatic finalUri BOOKMARKS_URI = Uri.parse( "content://browser/bookmarks"); 

如果權限依賴於提供給方法參數的特定值,那麼可以對參數本身使用 @RequiresPermission 而不用列出具體的權限,如 startActivity(intent) 方法:

publicabstractvoidstartActivity(@RequiresPermission Intent intent, @Nullable Bundle) {...} 

當我們使用這種方式(間接權限)時,構建工具將執行數據流分析以檢查傳遞到方法的參數是否具有任何 @RequiresPermission 註解。如:

Intent intent = newIntent(Intent.ACTION_CALL); 

intent.setData(Uri.parse( "tel:1234567890")); 

startActivity(intent); 

這裏的 startActivity(intent) 就直接報錯了:

callrequires permission which may be rejected byuser: code should explicitly checktosee ifpermission isavailable ( with

`checkPermission`) orexplicitly handle a potential `SecurityException`

因爲 Intent.ACTION_CALL 中標記了權限註解:

@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)

@RequiresPermission(Manifest.permission.CALL_PHONE)

publicstatic finalString ACTION_CALL = "android.intent.action.CALL"; 

@CheckResult

@CheckResult 註解是作用於方法上的,作用是檢驗有沒有處理返回值。如果沒有處理返回值則會報錯。

@CheckResult

publicString getData(String data) { 

returndata.trim(); 

線程註解

線程註解可以檢查某個方法是否從特定類型的線程調用。支持以下線程註解:

@MainThread:表示標記的方法只應在主線程調用。如果標記的是一個類,那麼該類中的所有方法都應該是在主線程被調用。例:(通常,應用程序的主線程也是 Ui 線程。但是,在特殊情況下,應用程序的主線程可能不是其 Ui 線程)@MainThread

publicvoiddeliverResult(D data){ ... } 

@UiThread:表示標記的方法或構造函數只應該在 Ui 線程上調用。如果標記的是一個類,那麼該類中的所有方法都應是在 Ui 線程被調用。例:@UiThread

publicabstractvoidsetText(@NonNull String text){...} 

@WorkerThread:表示標記的方法只應該在工作線程上調用。如果標記的是一個類,那麼該類中的所有方法都應是在一個工作線程上調用。例:@WorkerThread

protectedabstractFilterResults performFiltering(CharSequence constraint); 

@BinderThread:表示標記的方法只應在綁定線程上調用。如果標記的是一個類,那麼該類中的所有方法都應是在綁定線程被調用。例:@BinderThread

publicBeamShareData createBeamShareData(){ ... } 

@AnyThread:表示可以從任何線程調用帶標記的方法。如果標記的是一個類,那麼該類中的所有方法都可以從任何線程中調用。例:@AnyThread

publicvoiddeliverResult(D data){ ... } 

構建工具會將 @MainThread 和 @UiThread 註解視爲可以互換,因此,我們可以從 @MainThread 方法調用 @UiThread 方法,反之亦然。不過如果系統應用在不同線程上帶有多個試圖,Ui 線程可與主線程不同。因此,我們應該使用 @UiThread 標註於應用的視圖層次結構關聯的方法,使用 @MainThread 僅標註於應用生命週期關聯的方法。

資源註解

在 Android 中幾乎所有的資源都有其對於的 id,我們在使用的時候可以直接通過 id 來,如:

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

但是這樣如果沒有寫指定的資源註解的話就會風險,比如隨便傳了個 0,那麼就會找不到對應的資源。

爲了避免由於自己的粗心大意而引發的錯誤,我們就可以使用資源註解了,如:

publicintgetText(@StringRes intid){ 

這樣當我們調用該方法時,如果傳遞的參數並不是 String 類型的資源 id,那麼編譯器就會報錯提示。

除了 @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 類型資源。(複數) 

@RawRes:R.raw 類型資源。 

@StyleableRes:R.styleable 類型資源。 

@StyleRes:R.style 類型資源。 

@TransitionRes: R.transition 類型資源。 

@XmlRes:R.xml 類型資源。 

@AnyRes:未知資源。(表示自己不知道是什麼類型的資源。比如有可能爲 R.drawable 也有可能是 R.string。) 

@ColorInt

@ColorInt 註解的作用爲:限定顏色值。(ARGB:0xAARRGGBB)

publicvoidsetColor(@ColorInt intcolor){ 

如果直接使用資源 id,則會報錯,如下:

setColor(R.color.colorAccent) // 報錯

正確的使用是:

setColor(0xFFFF00FF); 

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

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

@CallSuper

該註解用於修飾方法,表示重寫該方法時必須調用 super 方法。如 onCreate() 方法:

@CallSuper

protectedvoidonCreate(Bundle savedInstanceState){ 

重寫 onCreate() 方法時,必須調用 super 方法:

super.onCreate(savedInstanceState); 

否則報錯。

@VisibleForTesting & @Keep

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

@VisibleForTesting:該註解只起到一個註釋的作用,告訴其他開發者被標記的代碼爲什麼有這麼大的可見程度(爲了測試方便)。因此,經常用來修飾 public 或 protected,用來修飾 private 並不會報錯,但是沒有意義。@Keep:標記的指定代碼在混淆時不會被混淆。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章