正式开始介绍之前,我们先来了解下注解是到底是什么?
注解
注解是一种可以添加到java代码中。类、方法、变量、参数、包都可以被注解,注解对被注解的代码没有直接影响。
注解之所以起作用是因为在代码编译时会根据相应的注解做对应的处理。
定义注解
注解使用关键字@interface进行定义的。
@Documented
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.METHOD, ElementType.PARAMETER,
ElementType.FIELD, ElementType.LOCAL_VARIABLE,
ElementType.ANNOTATION_TYPE, ElementType.PACKAGE})
public @interface Nullable {
}
但是在定义注解时需要使用@Target等注解对注解进行注解。用来对注解进行定义的注解就是元注解。
元注解
作用在其他注解的注解(或者说 元注解)是:
- @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
- @Documented - 标记这些注解是否包含在用户文档中。
- @Target - 标记这个注解应该是哪种 Java 成员。
- @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
引用自维基百科——Java注解
support.annotation
OverView
support.annotation是Google提供的注解库,与Android Studio内置的代码检查工具配合,注解可以帮助检测可能发生的问题,例如 null 指针异常和资源类型冲突等。
Android Studio配置
在Module的build.gradle中添加配置:
implementation 'com.android.support:support-annotations:28.0.0'
需要注意的是:如果您使用 appcompat 库,则无需添加 support-annotations 依赖项。因为 appcompat 库已经依赖注解库。
Nullness注解
添加 @Nullable 和 @NonNull 注解,以检查给定变量、参数或返回值的 nullness。@Nullable 注解指示可以为 null 的变量、参数或返回值,而 @NonNull 则指示不可为 null 的变量、参数或返回值。
private void testNullness(@NonNull Context context){
}
资源注解
验证资源类型可能非常有用,因为 Android 对资源(例如可绘制对象和字符串资源)的引用以整型形式传递。需要参数来引用特定类型资源(例如可绘制对象)的代码可以作为预计的引用类型 int 传入,不过实际将引用不同类型的资源,例如 R.string 资源。
@StringRes //字符串资源
@IntegerRes //整型资源
@ArrayRes //数组型资源
@BoolRes //布尔型资源
//...
@FontRes //字体资源
@InterpolatorRes
@ColorRes //颜色资源
@DrawableRes //Drawable资源
@AnimatorRes //动画资源
@AnyRes //任意资源
可以用来对方法的参数指定资源类型:
public void setColor(@ColorRes int color){
//指定参数为Color型资源,若传递R.string型资源,则会提示错误
}
线程注解
线程注解可以检查某个方法是否从特定类型的线程调用。
@MainThread //主线程
@UiThread //UI线程
@WorkerThread //工作线程
@BinderThread //
@AnyThread //任意线程
值约束注解
可以约束某个参数的取值范围,或者长度。
@IntRange //int范围
@FloatRange //float范围
@Size //检查集合、数组和字符串的长度,min=1,max=3,@size(3)
例如:
private int setAlpha(@IntRange(from = 0, to = 255) int alpha){return alpha;}
private float setAlpha(@FloatRange(from = 0.0,to = 1.0) float alpha){return alpha;}
private void setSize(@Size(3) int[] array){} //参数长度为3
private void setSize(@Size(min = 1) float[] array){} //参数至少有一个元素
private void setSize(@Size(max = 3) String[] array){} //参数最多有三个元素
权限注解
检查该方法使用到的权限是否在权限列表中存在。
@RequiresPermission //权限注解,
//anyOf 检查一组中的任意一个权限
//allOf 检查一组权限
例如:
@RequiresPermission(Manifest.permission.SET_WALLPAPER)
public void setWallpaper() throws IOException{}
@RequiresPermission(allOf = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE})
public static final void copyFile(String dest, String source) {}
返回值注解
检查是否对方法的返回值进行处理,验证实际使用的是方法的结果还是返回值。
例如:
@CheckResult(suggest = "check(int pid)")
public int check(int pid, int uid){return 0;}
public void check(int pid){}
Typedef 注解
使用 @IntDef 和 @StringDef 注解,以便能够创建整型和字符串集的枚举注解来验证其他类型的代码引用。看代码更容易理解一些:
//定义了两个常量
public static final int REQUEST_TYPE_AQIYI = 0;
public static final int REQUEST_TYPE_LOCAL = 1;
//定义一个RequestType声明可接收的常量
@IntDef({REQUEST_TYPE_AQIYI,REQUEST_TYPE_LOCAL})
public @interface RequestType{}
@RequestType
public int getRequestType(){
//返回值只能是REQUEST_TYPE_AQIYI和REQUEST_TYPE_LOCAL的其中一个
//若不是则会生成警告
return REQUEST_TYPE_AQIYI;
}
public void requestMovieData(@RequestType int type){
//返回值只能是REQUEST_TYPE_AQIYI和REQUEST_TYPE_LOCAL的其中一个
//若不是则会生成警告
}
本篇诸多描述引用自Android官方文档——使用注解改进代码检查有条件的小伙伴可以直接查看源文档,原文档描述更详细一些。