使用代码检查工具,例如Lint,能帮助你找到代码中的问题。但有时候检查工具检查的程度还不够,比如说,Android的资源文件 id 统一是 int类型,用来标识 字符串、图片、颜色及其它类型的资源。如果你在本应该使用颜色资源id的地方使用了字符串资源的id,检查工具就无法检查出来,即使这种情况会导致渲染出错甚至app崩溃。而使用Annotations就能检查出上述的问题,当然,Annotations技不只此,后面会详细介绍。
在项目中添加Annotations
1. 导入 support-annotations 包
在build.gradule
文件里引入support-annotations
包
dependencies {
... ...
compile 'com.android.support:support-annotations:26.1.0'
}
如果项目里已经引用了
appcompat
包,就不必再添加support-annotations
引用了。因为appcompat
包已经添加了对support-annotations
的引用。
2. 运行代码检查
点击Android Studio菜单栏上的 Analyze > Inspect Code 运行代码检查,就会得到一份检查结果,如下图:
结果里列出了检查到的所有问题,甚至还会给出解决建议,点击某一条问题,可以直接定位到问题所在的代码。当然,检查出的这些问题,并不会影响或阻止app的编译,它们只是检查工具给出的警告。
接下来一一介绍Annotations的注解标签
1. 空态注解(Nullness)
1.1 @Nullable 和 @NonNull
使用 @Nullable
和 @NonNull
来检查变量、参数或者返回值的空态。@Nullbale
表示变量、参数或者返回值可以为空,而@NonNull
表示不能为空。
下面这段代码,表示当 onCrateView
的时候,传入的 Context
和 AttributeSet
不能为空,而且其返回值也不能为空。
import android.support.annotation.NonNull;
...
/** Add support for inflating the <fragment> tag. **/
@NonNull
@Override
public View onCreateView(String name, @NonNull Context context, @NonNull AttributeSet attrs) {
...
}
1.2 可空分析
请忽略这僵硬的翻译。
Android Studio 提供自动分析代码(参数、变量、返回值)是否可以为空的功能。分析完成之后,你可以选择是否自动为代码添加@Nullable
或者 @NonNull
注释。
点击Android Studio菜单栏上的 Analyze > Infer Nullity,进行可空分析,会得到如下图的结果:
可以选择整个项目,也可以选择其中一部分,点击 Infer Nullity Annotations 按钮,自动为代码添加@Nullable
或 @NonNull
注释。
要进行可空分析,必须在
build.gradle
文件里引用support-annotations
包,即使原来已经添加了appcompat
包。
2. 资源注解(Resource)
区分Android的资源类型非常有必要,因为Android的资源引用,无论是string资源还是 drawable资源等,都是用int类型表示。
下面这个方法通过对参数添加@StringRes
注解,要求调用此方法时,必须传入一个string资源。
public abstract void setTitle(@StringRes int resId) { … }
资源的类型非常之多,还有一些注解标签,比如:@DrawableRes
, @DimenRes
, @ColorRes
, and @InterpolatorRes
我想都不用解释,一看就能明白。还有一个@AnyRes
,表示资源类型未知,或者可以传入多种类型。全部标签请见官方文档
3. 线程注解(Thread)
线程注解用来表明某个方法运行在特定线程。所有线程标签如下:
- @MainThread
- @UiThread
- @WorkerThread
- @BinderThread
- @AnyThread
给一个示例代码:
@UiThread
public abstract void setTitle(@StringRes int resId) { … }
4. 数值约束注解
@IntRange
, @FloatRange
分别用来约束int类型,float类型数值范围,@Size
用来约束 集合、数组或者字符串的长度。
以下代码使用@IntRange
约束参数alpha的取值的范围在0到255之间。
public void setAlpha(@IntRange(from=0,to=255) int alpha) { … }
@Size
有四种用法
- 限定最小值 (such as @Size(min=2)
)
- 限定最大值 (such as @Size(max=2)
)
- 必须为某个值 (such as @Size(2)
)
- 必须是某个值的倍数 (such as @Size(multiple=2)
)
提供一个例子,以下代码要求传入的location数组长度至少为1.
int[] location = new int[3];
button.getLocationOnScreen(@Size(min=1) location);
5. 权限(Permission )注解
使用@RequiresPermission
注解表明某方法的执行需要某(些)权限。
如果只需要某一个权限。比如需要一个设置墙纸权限,如下:
@RequiresPermission(Manifest.permission.SET_WALLPAPER)
public abstract void setWallpaper(Bitmap bitmap) throws IOException;
如果需要一组权限,比如读写SD卡权限,如下:
@RequiresPermission(allOf = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE})
public static final void copyFile(String dest, String source) {
...
}
还有更复杂的用法,不过感觉目前我用不到,就不写了。。。
6. 方法的返回值注解
使用@CheckResult
注解,来验证方法的返回值是否被使用了。这个注解用来帮助方法的使用者留意容易被误解的方法,如果使用者调用了被@CheckResult
注解的方法而没有使用其返回值,就会得到一个警告。
7. CallSuper注解
如果API允许使用者重写某个方法,但是重写的时候必须调用父类方法,这时就可以对父类方法使用@CallSuper
注解。
比如下面这个方法,当子类重写onCreate
方法的时候,必须调用super.onCreate()
。
@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}
以上列出了大部分常用的注解,当然还不是全部。如果想了解
support-annotations
包里全部的注解,可以参考Annotations注解列表 以及 官方使用指南