使用 Annotations 改进代码检查

来源:互联网 发布:网络访问控制技术应用 编辑:程序博客网 时间:2024/06/10 05:08

使用代码检查工具,例如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 的时候,传入的 ContextAttributeSet 不能为空,而且其返回值也不能为空。

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

给一个示例代码:

@UiThreadpublic 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()

@CallSuperprotected void onCreate(Bundle savedInstanceState) {}


以上列出了大部分常用的注解,当然还不是全部。如果想了解support-annotations包里全部的注解,可以参考Annotations注解列表 以及 官方使用指南

原创粉丝点击