轉載請標明出處: juejin.im/post/59bf5e…
本文出自:周遊的主頁 html
Android Support Library 從 19.1 版本開始引入了一個新的註解庫,其中包含了不少的元註解,使用它們修飾咱們的代碼, 可讓咱們提升程序的開發效率,讓咱們更早的發現問題。以及對代碼施以規範,讓代碼更加有可讀性。這篇文章就來簡單瞭解下這些註解,以及其使用。若有錯誤和遺漏,歡迎留言或補充~android
注:如今咱們新建項目直接就依賴了 support.appcompat 包,其中已經依賴了 annotations 包。若是你的項目中寫以下註解報錯,能夠添加註解包:數組
dependencies { compile 'com.android.support:support-annotations:22.2.0' }複製代碼
替代 Java 中枚舉的註解,以 @IntDef 爲例,定義和使用以下:bash
@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){
}複製代碼
若是容許常量與標誌(例如:|、& 和 ^ 等等)相結合,則咱們可使用 flag 屬性,如:app
@IntDef(flag = true, value = {RED, BLUE, YELLOW})複製代碼
使用:函數
setColor(RED | BLUE);複製代碼
上面的註解能夠修飾以下元素:
1,方法參數。如:工具
@Nullable
private String data;複製代碼
2,方法的返回值。 如:post
@Nullable
public String getData(){
return data;
}複製代碼
3,成員屬性。如:測試
public void setData(@Nullable String data){
}複製代碼
當用空的參數傳給被 @NonNull 修飾的方法參數的方法時,會給出以下警告提示(編譯不會報錯):ui
passing "null" argument to parameter annotated as @NotNull複製代碼
@FloatRange 和 @IntRange 是用於限定範圍的註解。其中 @FloatRange 是限定 float 類型的,而 @IntRange 是限定 int 類型的。它們同上註解同樣,能夠修飾方法參數、方法返回值、成員屬性。
以 @IntRange 爲例,修飾方法參數的定義以下:
public void setAge(@IntRange(from = 1, to = 180) int age){
}複製代碼
若是調用該方法傳的參數不在 1 - 180 的範圍內, 如:setAge(0),那麼編譯會直接報以下錯:
value must be ≥ 1 and ≤ 180 (was 0)複製代碼
@Size 註解的做用是限定長度的,同上註解同樣,能夠修飾方法參數、方法返回值、成員屬性。
public void setData(@Size(4) String data){
}複製代碼
當傳入的字符串長度不等於 4 時,編譯器會直接報錯:Length must be exactly 4複製代碼
public void setData(@Size(4) int[] data){
}複製代碼
public void setData(@Size(multiple = 2) int[] data){
}複製代碼
限定最小的長度:@Size(min = 2)複製代碼
限定最大的長度:@Size(max = 2)複製代碼
等同於 @Size(2)
寫法:@Size(value = 2)複製代碼
該註解做用是代表方法所執行的內容須要權限。如須要單個權限:
@RequiresPermission(Manifest.permission.CALL_PHONE)
private void callPhone(String phone){
}複製代碼
須要一組權限:
@RequiresPermission(allOf = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE})
public static final void copyFile(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))
public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks");複製代碼
若是權限依賴於提供給方法參數的特定值,那麼能夠對參數自己使用 @RequiresPermission 而不用列出具體的權限,如 startActivity(intent) 方法:
public abstract void startActivity(@RequiresPermission Intent intent, @Nullable Bundle) {...}複製代碼
當咱們使用這種方式(間接權限)時,構建工具將執行數據流分析以檢查傳遞到方法的參數是否具備任何 @RequiresPermission 註解。如:
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:1234567890"));
startActivity(intent);複製代碼
這裏的 startActivity(intent) 就直接報錯了:
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`複製代碼
由於 Intent.ACTION_CALL 中標記了權限註解:
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@RequiresPermission(Manifest.permission.CALL_PHONE)
public static final String ACTION_CALL = "android.intent.action.CALL";複製代碼
@CheckResult 註解是做用於方法上的,做用是檢驗有沒有處理返回值。若是沒有處理返回值則會報錯。
@CheckResult
public String getData(String data) {
return data.trim();
}複製代碼
線程註解能夠檢查某個方法是否從特定類型的線程調用。支持如下線程註解:
@MainThread:表示標記的方法只應在主線程調用。若是標記的是一個類,那麼該類中的全部方法都應該是在主線程被調用。例:(一般,應用程序的主線程也是 Ui 線程。可是,在特殊狀況下,應用程序的主線程可能不是其 Ui 線程)
@MainThread
public void deliverResult(D data) { ... }複製代碼
@UiThread:表示標記的方法或構造函數只應該在 Ui 線程上調用。若是標記的是一個類,那麼該類中的全部方法都應是在 Ui 線程被調用。例:
@UiThread
public abstract void setText(@NonNull String text) {...}複製代碼
@WorkerThread:表示標記的方法只應該在工做線程上調用。若是標記的是一個類,那麼該類中的全部方法都應是在一個工做線程上調用。例:
@WorkerThread
protected abstract FilterResults performFiltering(CharSequence constraint);複製代碼
@BinderThread:表示標記的方法只應在綁定線程上調用。若是標記的是一個類,那麼該類中的全部方法都應是在綁定線程被調用。例:
@BinderThread
public BeamShareData createBeamShareData() { ... }複製代碼
@AnyThread:表示能夠從任何線程調用帶標記的方法。若是標記的是一個類,那麼該類中的全部方法均可以從任何線程中調用。例:
@AnyThread
public void deliverResult(D data) { ... }複製代碼
構建工具會將 @MainThread 和 @UiThread 註解視爲能夠互換,所以,咱們能夠從 @MainThread 方法調用 @UiThread 方法,反之亦然。不過若是系統應用在不一樣線程上帶有多個試圖,Ui 線程可與主線程不一樣。所以,咱們應該使用 @UiThread 標註於應用的視圖層次結構關聯的方法,使用 @MainThread 僅標註於應用生命週期關聯的方法。
在 Android 中幾乎全部的資源都有其對於的 id,咱們在使用的時候能夠直接經過 id 來,如:
textView.setText(getResources().getText(R.string.app_name));複製代碼
可是這樣若是沒有寫指定的資源註解的話就會風險,好比隨便傳了個 0,那麼就會找不到對應的資源。
爲了不因爲本身的粗枝大葉而引起的錯誤,咱們就可使用資源註解了,如:
public int getText(@StringRes int id){
}複製代碼
這樣當咱們調用該方法時,若是傳遞的參數並非 String 類型的資源 id,那麼編譯器就會報錯提示。
除了 @StringRes
資源註解外,還有:
@ColorInt 註解的做用爲:限定顏色值。(ARGB:0xAARRGGBB)
public void setColor(@ColorInt int color) {
}複製代碼
若是直接使用資源 id,則會報錯,以下:
setColor(R.color.colorAccent)// 報錯複製代碼
正確的使用是:
setColor(0xFFFF00FF);複製代碼
若是要使用資源 id,則能夠經過 ContextCompat.getColor() 方法來:
setColor(ContextCompat.getColor(context, R.color.colorAccent));複製代碼
該註解用於修飾方法,表示重寫該方法時必須調用 super 方法。如 onCreate() 方法:
@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}複製代碼
重寫 onCreate() 方法時,必須調用 super 方法:
super.onCreate(savedInstanceState);複製代碼
不然報錯。
使用 @VisibleForTesting 和 @Keep 註解能夠表示方法、類、或字段的可訪問性。
參考: