Support Annotation Library 是一个元注解包,它主要用来帮助开发者在编译期间发现可能存在的BUG。
其原理就是通过注解标记的方式,标记传参和返回,从而启动规范传参和返回的作用。
1. Nullness注解
- @Nullable 作用于函数参数或者返回值,标记参数或者返回值可以为空。
- @NotNull 作用于函数参数或者返回值,标记参数或者返回值不可以为空。
2. 资源类型注解
资源类型的注解作用于函数参数,返回值及类的变量。每种资源会对应一个注解。
- AnimationRes:标记整型值是android.R.animator 类型(animator文件夹下存放property
animation(属性动画)) - AnimRes:标记整型值是android.R.anim 类型 (文件夹下存放tween animation(补间动画)和frame animation(逐帧动画))
- AnyRes:标记整型值是任何一种资源类型,如果确定知道表示的是哪一种具体资源的话,建议显示指定。
- ArrayRes:标记整型值是android.R.array 类型
- AttrRes:标记整型值是android.R.attr 类型
- BoolRes:标记整型值是布尔类型
- ColorRes:标记整型值是颜色类型
- DrawableRes:标记整型值是android.R.drawable 类型
- IdRes:标记整型值是android.R.id 类型
- IntegerRes:标记整型值是android.R.integer 类型
- InterpolatorRes:标记整型值是android.R.interpolator 类型
- LayoutRes:标记整型值是android.R.layout 类型
- MenuRes:标记整型值是android.R.menu 类型
- PluralsRes:标记整型值是android.R.plurals 类型,表示复数字符串类型
- RawRes:标记整型值是android.R.raw 类型
- StringRes:标记整型值是android.R.string 类型
- StyleableRes:标记整型值是android.R.styleable 类型
- StyleRes:标记整型值是android.R.style 类型
- TransitionRes:标记整型值是android.R.transition 类型
- XmlRes:标记整型值是android.R.xml 类型
基本上所有的我们在开发中有所涉及的资源属性都可以使用资源型注解进行标记。
3. 类型定义注解
在Android开发中,整型值不止经常用来代表资源引用值,而且经常用来代替枚举值。
@IntDef 注解用来创建一个整型类型定义的新注解,我们可以使用这个新注解来标记自己编写的API
@IntDef(flag=true ,value={
VALUE1.VALUE2,VALUE3})
@Retention(RetentionPolicy.SOURCE)
public @interface ControlValue{
}
//尽可返回 VALUE1.VALUE2,VALUE3
@ControlValue
public abstract int getValue();
//只能传入控制的值
public void setValue(@ControlVaue int value);
4. 线程注解
Android 应用开发中经常会涉及多线程的使用,界面相关操作必须在主线程,而耗时操作需要在后台线程中。线程注解有四种。
-
@UiThread
标记运行在UI线程,一个UI线程是Activity运行所在的主窗口,对于一个应用而言,可能存在多个UI线程,每个UI线程对应不同的主窗口。 -
@MainThread
标记运行在主线程,一个应用只有一个主线程,主线程也是@UiThread线程。
通常情况下,我们使用@MainThread来注解生命周期相关函数,使用@UiThread来注解视图相关的函数。
一般情况下@MainThread和@UiThread是可互换使用的。 -
@WorkerThread:标记运行在后台线程
-
@BinderThread:标记运行在Binder线程
一个典型的使用就是AsyncTask:
@WorkerThread
protected abstract Result doInBackground(Params... params);
@MainThread
protected void onPreExecute() {
}
@MainThread
protected void onPostExecute(Result result) {
}
@MainThread
protected void onProgressUpdate(Progress... values) {
}
@MainThread
protected void onCancelled(Result result) {
onCancelled();
}
5. RGB 颜色值注解
我们使用@ColorRes来标记传入的类型值是颜色类型的资源id。
@ColorInt 注解标记参数类型需要传入RGB或ARGB颜色整型值。
//@param color A color value in the form 0xAARRGGBB
public void setTextColor(@ColorInt int color)
6. 值范围注解
当函数参数的取值在一定范围内时,可以使用值范围注解来防止调用者参入错误的参数。
- @Size:对于类似数组、集合和字符串之类的参数,我们可以使用
- @Size注解来表示这些参数的大小。
- @Size(min=1)//表示结合不可以为空
- @Size(max=23)//表示字符串最大字符个数是23
- @Size(2)//表示数组元素个数是2个
- @Size(multiple=2)//表示数组大小是2的倍数
- @IntRange:参数类型是int 或者Iong
public void setAlpha(@IntRange(from=0,to=255) int alpha)
- @FloatRange:参数类型是float或者double
public void setAlpha(@FloatRange(from=0.0,to=1.0) float alpha)
7. 权限注解
Android应用在使用某些系统功能时,需要在AndroidManifest.xml中声明权限,否则在运行时会缺失对应的权限。为了在编译阶段及时发现缺失的权限,我们可以使用 @RequiredPermission 注解。
@Retention(CLASS)
@Target({
ANNOTATION_TYPE,METHOD,CONSTRUCTOR,FIELD,PARAMETER})
public @interface RequiresPermission {
/**
* The name of the permission that is required, if precisely one permission
* is required. If more than one permission is required, specify either
* {@link #allOf()} or {@link #anyOf()} instead.
* <p>
* If specified, {@link #anyOf()} and {@link #allOf()} must both be null.
*/
String value() default "";
/**
* Specifies a list of permission names that are all required.
* <p>
* If specified, {@link #anyOf()} and {@link #value()} must both be null.
*/
String[] allOf() default {
};
/**
* Specifies a list of permission names where at least one is required
* <p>
* If specified, {@link #allOf()} and {@link #value()} must both be null.
*/
String[] anyOf() default {
};
/**
* If true, the permission may not be required in all cases (e.g. it may only be
* enforced on certain platforms, or for certain call parameters, etc.
*/
boolean conditional() default false;
/**
* Specifies that the given permission is required for read operations.
* <p>
* When specified on a parameter, the annotation indicates that the method requires
* a permission which depends on the value of the parameter (and typically
* the corresponding field passed in will be one of a set of constants which have
* been annotated with a {@code @RequiresPermission} annotation.)
*/
@Target({
FIELD, METHOD, PARAMETER})
@interface Read {
RequiresPermission value() default @RequiresPermission;
}
/**
* Specifies that the given permission is required for write operations.
* <p>
* When specified on a parameter, the annotation indicates that the method requires
* a permission which depends on the value of the parameter (and typically
* the corresponding field passed in will be one of a set of constants which have
* been annotated with a {@code @RequiresPermission} annotation.)
*/
@Target({
FIELD, METHOD, PARAMETER})
@interface Write {
RequiresPermission value() default @RequiresPermission;
}
}
8. 重写函数注解
如果API允许调用者重写某个函数,但同时要求重写的函数需要调用被重写的函数,否则代码逻辑可能会错误,那么可以使用 @CallSuper 注解来提示开发者。
@CallSuper
@Override
protected void onSaveInstanceState(@NonNull Bundle outState)
9. 返回值注解
如果我们编写函数需要调用者对返回值做某些处理,那么可以使用 @CheckResult 注解来提示开发者。
@CheckResult(suggest="#enforcePermission(String,int,int,String)")
@PackageManager.PermissionResult
public abstract int checkPermission(@NonNull String permission, int pid, int uid);
这样调用者如果没有检查这两个函数的返回值,那么Android Studio 将会给出警告,警告信息中包含suggest属性中的内容。
10. @VisibleForTesting
单元测试可能需要访问到一些不可见的类、函数或者变量,这时可以使用 @VisibleForTesting 注解来时其对测试可见。
11. @Keep
@Keep 注解用来标记Proguard混淆过程中不需要混淆的类或者方法。
最后,如果函数库中使用 Annotation Library,并使用Gradle生成的aar压缩包,那么在编译时Android Gradle插件会抽取出这些注解信息并打包在aar文件中,以便函数库的调用者可以正确的使用我们的注解信息。
aar中的 annotations.zip 文件就是抽取出来的注解信息。