转载请标明出处: 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 注解能够表示方法、类、或字段的可访问性。
参考: