这边文章主要讨论源码级别(RetentionPolicy.SOURCE)的注解,站在巨人的肩膀上来捋一捋。
代码地址:android-annotation-tutorial
从 19.1 开始出现,Android Annotation是以Support Library的形式给我们提供的,只需要在app的gradle文件下添加如下即可。
implementation 'com.android.support:support-annotations:version'
在android.support.annotation包下面有如下:
[图片上传失败...(image-d47d42-1536888959292)]
这里大部分注解都是源码级别的注解,其他的暂不讨论。
-
空注解
作用于函数参数和返回值 , 标记参数或者返回值是否可以为空
注解符号 | 标记类型 |
---|---|
@Nullable | 可空 |
@NonNull | 非空 |
举例:
- 我们在Activity 的onCreate方法中已经能看到该注解的身影:
[图片上传失败...(image-157325-1536888959292)]
我们添加如下方法:
@NonNull
String testNull(@Nullable String arg) throws Exception{
if(TextUtils.isEmpty(arg)){
// throw new NullPointerException("testNull arg is null.");
return null;
}
return arg;
}
若返回null,则文字显示灰色提示如下:
[图片上传失败...(image-3a4d11-1536888959292)]
显然我们发现这个问题时就能及时处理将它扼杀在摇篮里。
-
资源类注解
Android 中的资源都是通过 R 文件来访问的,R 文件通过整形值来标识不同的资源。
但是如果需要一个Layout 资源 ID 时,传递了颜色资源的 ID 时,编译时不会报错,运行时才会崩溃。那就可以用如下的注解来避免这种尴尬。
注解符号 | 标记类型 |
---|---|
@AnimatorRes | android.R.animator |
@AnimRes | android.R.anim |
@ArrayRes | android.R.array |
@AttrRes | android.R.attr |
@BoolRes | android.R.bool |
@ColorRes | android.R.color |
@DimenRes | android.R.dimen |
@DrawableRes | android.R.drawable |
@IdRes | android.R. id |
@LayoutRes | android.R.layout |
@RawRes | android.R.raw |
@StyleableRes | android.R.styleable |
@StyleRes | android.R.style |
@XmlRes | android.R.xml |
@InterpolatorRes | android.R.interpolator |
@AnimatorRes | android.R.animator |
@AnimRes | android.R.anim |
@ArrayRes | android.R.array |
@AttrRes | android.R.attr |
@BoolRes | android.R.bool |
@ColorRes | android.R.color |
@DimenRes | android.R.dimen |
@DrawableRes | android.R.drawable |
@IdRes | android.R. id |
@LayoutRes | android.R.layout |
@RawRes | android.R.raw |
@StyleableRes | android.R.styleable |
@StyleRes | android.R.style |
@XmlRes | android.R.xml |
@InterpolatorRes | android.R.interpolator |
举例:
我们添加如下方法:
public void setTitle(@StringRes int resId) {
}
调用该方法时如果传入了错误的类型,编译时就会报错。
[图片上传失败...(image-299403-1536888959292)]
-
线程注解
注解符号 | 标记类型 |
---|---|
@MainThread | 运行在主线程 |
@UiThread | 运行在 UI 线程 |
@WorkerThread | 运行在后台线程 |
@BinderThread | 运行在Binder线程中 |
@AnyThread | 可以运行在任意线程中 |
在AsyncTask源码中各个方法注解的明明白白的,摘取一部分:
[图片上传失败...(image-1af1f9-1536888959292)]
举个例子:
我们在类中添加如下代码:
private TextView tv ;
@UiThread
public void uiThreadTest(){
tv.setText("success");
}
@WorkerThread
public void workerThreadTest(){
tv.setText("error");
}
注解为@WorkerThread的方法提示了错误,不能在工作线程中更新UI。
[图片上传失败...(image-988c80-1536888959292)]
说明:在Android 系统中,主线程就是 UI 线程,所以,编译工具对待 @MainThread 和 @UiThread 是同等对待的,然后,我们在使用注解的时候应该区别使用,和UI相关的代码注解使用 @UiThread,其他和 APP 生命周期相关的代码才使用 @MainThread
-
值约束注解
注解符号 | 标记类型 |
---|---|
@IntRange | 限定 int 类型的取值范围 |
@FloatRange | 限定 float 类型的取值范围 |
@Size | 限定元素的大小或者长度 |
举例:
我们在ActivityCompat类下找到了@IntRange的使用例子
[图片上传失败...(image-5f4a3c-1536888959292)]
下面我们自己来写个例子:
// a,限定 alpha 参数的取值范围为 0 至255
public void setAlpha(@IntRange(from=0,to=255) int alpha) {
}
// b,限定 alpha 参数的取值范围为 0.0 至 1.0
public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
}
// c,限定 location 数组大小为 2
public void getLocationInWindow(@Size(2) int[] location) {
}
// d,限定 location 参数的最小值为 1
public void getLocationOnScreen(@Size(min=2) int[]location){
}
如下是我们自己故意错误调用时编译器泛红了:
[图片上传失败...(image-b6e04d-1536888959292)]
-
权限注解
检查方法调用者是否具备相应的权限
注解符号 | 标记类型 |
---|---|
@RequiresPermission | 调用所需要具备的权限 |
举例:
@RequiresPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
public void readFile(String dest, String source) {
}
@RequiresPermission(allOf = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE})
public static final void copyFile(String dest, String source) { }
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void getLastKnownLocation(String provider){
}
-
类型定义注解
使用 @IntDef 和@StringDef 注解,定义一组枚举类型的注解来校验参数的类型,限定参数的取值范围 ,这个也是比较推荐替代 enmu 的做法
注解符号 | 标记类型 |
---|---|
@IntDef 定义 | int 类型的数据 |
@StringDef | 定义 String 类型数据 |
自己写个demo:
static class EnumItem {
public static final int TYPE0 = 0;
public static final int TYPE1 = 1;
public static final int TYPE2 = 2;
@IntDef({TYPE0, TYPE1, TYPE2})
public @interface ItemType {
}
int mType;
public void setType(@ItemType int type) {
this.mType = type;
}
}
-
@CheckResult注解
当调用没有正确调用方法时,提示调用者对返回值进行检查处理, 使用 suggest 编写提示内容
@CheckResult(suggest= "建议你调用前判断一下是否为空?")
public String getCheckResultValue(String arg){
return arg;
}
[图片上传失败...(image-b2f0e1-1536888959292)]
-
@Keep 注解
标记在混淆时不需要混淆该方法
-
@CallSuper 注解
标记子类在复写父类方法的时候,必须调用父类的该方法。
最后
Android Support Annotations 注解来优化我们的代码,增加可读性的同时,也让让更多的错误消灭在萌芽之中。但是如果你是一个开发熟手这些注解真的能给你带来效率吗?
参考链接: