dependencies {
implementation 'com.android.support:support-annotations:28.0.0'
}
注解项如下:
- @NonNull
- @Nullable
- @StringRes
- @DrawableRes
- @DimenRes
- @ColorRes
- @InterpolatorRes
- @AnyRes
- @ColorInt
- @MainThread
- @WorkerThread
- @BinderThread
- @UiThread
- @AnyThread
- @IntRange
- @FloatRange
- @Size
- @RequiresPermission
- @CheckResult
- @CallSuper
- @IntDef
- @StringDef
- @Keep
- @VisibleForTesting
- @RestrictTo
- @SdkConstant
- @Override
覆盖父类方法 @Override是伪代码,表示重写(当然不写也可以),不过写上有如下好处: 1、可以当注释用,方便阅读; 2、编译器可以给你验证@Override下面的方法名是否是你父类中所有的,如果没有则报错。例如,你如果没写@Override,而你下面的方法名又写错了,这时你的编译器是可以编译通过的,因为编译器以为这个方法是你的子类中自己增加的方法。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_banner_view_pager_2);
initViews();
initData();
setSelectedIndicator(0);
}
源码如下:
package java.lang;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
ElementType
package java.lang.annotation;
public enum ElementType {
TYPE,
FIELD,
METHOD,
PARAMETER,
CONSTRUCTOR,
LOCAL_VARIABLE,
ANNOTATION_TYPE,
PACKAGE,
TYPE_PARAMETER,
TYPE_USE;
private ElementType() {
}
}
RetentionPolicy
package java.lang.annotation;
public enum RetentionPolicy {
SOURCE,
CLASS,
RUNTIME;
private RetentionPolicy() {
}
}
@Target
注解的作用目标
package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE})
public @interface Target {
ElementType[] value();
}
@Target(ElementType.TYPE) //接口、类、枚举
@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR) //构造函数
@Target(ElementType.LOCAL_VARIABLE)//局部变量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包
@Retention注解的保留位置
package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE})
public @interface Retention {
RetentionPolicy value();
}
@Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Documented说明该注解将被包含在javadoc中
package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE})
public @interface Documented {
}
java中元注解有四个: @Retention @Target @Document @Inherited; @Inherited:说明子类可以继承父类中的该注解
@NonNull添加 @Nullable 和 @NonNull 注解,以检查给定变量、参数或返回值的 null 性。@Nullable 注解用于指明可以为 null 的变量、参数或返回值,而 @NonNull 则用于指明不可以为 null 的变量、参数或返回值。
import android.support.annotation.NonNull;
...
/** Add support for inflating the tag. **/
@NonNull
@Override
public View onCreateView(String name, @NonNull Context context,
@NonNull AttributeSet attrs) {
...
}
...
Android Studio 支持运行 null 性分析,以在代码中自动推断和插入 null 性注解。null 性分析会在代码的整个方法层次结构中扫描协定元素,以检测:
可以返回 null 的调用方法 不应返回 null 的方法 可以为 null 的变量,如字段、局部变量和参数 不能具有 null 值的变量,如字段、局部变量,以及参数 然后,该分析会在检测到上述方法或变量的位置自动插入适当的 null 注解。
要在 Android Studio 中运行 null 性分析,请依次选择 Analyze > Infer Nullity。Android Studio 会在代码中检测到上述方法或变量的位置插入 Android @Nullable 和 @NonNull 注解。运行 null 性分析后,最好验证一下这些注入的注解。
源码如下:
package android.support.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.ANNOTATION_TYPE, ElementType.PACKAGE})
public @interface NonNull {
}
@StringRes
验证资源类型可能非常有用,因为 Android 对资源(如可绘制对象和字符串资源)的引用以整数形式传递。如果代码需要一个参数来引用特定类型的资源(例如可绘制对象),可以为该代码传递预期的引用类型 int,但它实际上会引用其他类型的资源,如 R.string 资源。
例如,添加 @StringRes 注解,以检查资源参数是否包含 R.string 引用,如下所示:
public abstract void setTitle(@StringRes int resId)
@IntRange
@IntRange 注解可以验证整型或长整型参数值是否在指定范围内。以下示例可以确保 alpha 参数包含 0 到 255 之间的整数值:
public void setAlpha(@IntRange(from=0,to=255) int alpha) { ... }
@FloatRange
@FloatRange 注解可以检查浮点型或双精度型参数值是否在指定的浮点值范围内。以下示例可以确保 alpha 参数包含 0.0 到 1.0 之间的浮点值:
public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {...}
@Size
@Size 注解可以检查集合或数组的大小,以及字符串的长度。@Size 注解可用于验证以下特性:
最小大小(例如 @Size(min=2)) 最大大小(例如 @Size(max=2)) 确切大小(例如 @Size(2)) 大小必须是指定数字的倍数(例如 @Size(multiple=2)) 例如,@Size(min=1) 可以检查某个集合是否不为空,@Size(3) 可以验证某个数组是否正好包含三个值。以下示例可以确保 location 数组至少包含一个元素:
void getLocation(View button, @Size(min=1) int[] location) {
button.getLocationOnScreen(location);
}
@RequiresPermission
使用 @RequiresPermission 注解可以验证方法调用方的权限。要检查有效权限列表中是否存在某个权限,请使用 anyOf 属性。要检查是否具有某组权限,请使用 allOf 属性。以下示例会为 setWallpaper() 方法添加注解,以确保方法调用方具有 permission.SET_WALLPAPERS 权限。
@RequiresPermission(Manifest.permission.SET_WALLPAPER)
public abstract void setWallpaper(Bitmap bitmap) throws IOException;
以下示例要求 copyImageFile() 方法的调用方具有对外部存储空间的读取权限,以及对复制的映像中的位置元数据的读取权限:
@RequiresPermission(allOf = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_MEDIA_LOCATION})
public static final void copyImageFile(String dest, String source) {
//...
}
如果您需要对内容提供程序拥有单独的读取和写入访问权限,则需要将每个权限要求封装在 @RequiresPermission.Read 或 @RequiresPermission.Write 注解中:
@RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS))
@RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS))
public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks");
间接权限 如果权限依赖于为某个方法的参数提供的特定值,则应对该参数本身使用 @RequiresPermission,而不必列出具体权限。例如, startActivity(Intent) 方法会对传递给它的 intent 使用间接权限
public abstract void startActivity(@RequiresPermission Intent intent, @Nullable Bundle)
@SdkConstant
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@RequiresPermission(Manifest.permission.CALL_PHONE)
public static final String ACTION_CALL = "android.intent.action.CALL";
@CheckResult
使用 @CheckResult 注解可验证是否实际使用了方法的结果或返回值。不应使用 @CheckResult 为每个非 void 方法添加注解,而应添加注解来阐明可能令人不解的方法的结果。例如,Java 开发新手经常误认为 .trim() 会移除原始字符串中的空白字符。如果使用 @CheckResult 为方法添加注解,系统会在调用方不对方法的返回值进行任何处理时标记使用 .trim() 的情况。
以下示例为 checkPermissions() 方法添加了注解,以确保会实际引用该方法的返回值。此外,这还会将 enforcePermission() 方法指定为要向开发者建议的替代方法:
@CheckResult(suggest="#enforcePermission(String,int,int,String)")
public abstract int checkPermission(@NonNull String permission, int pid, int uid);
@CallSuper
使用 @CallSuper 注解可验证重写方法是否会调用该方法的超类实现。以下示例为 onCreate() 方法添加了注解,以确保所有重写方法实现都会调用 super.onCreate():
@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}
@VisibleForTesting
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
void myMethod() { ... }
Typedef 注解
使用 @IntDef 和 @StringDef 注解,您可以创建整数集和字符串集的枚举注解来验证其他类型的代码引用。Typedef 注解可以确保特定参数、返回值或字段引用一组特定的常量。这些注解还会启用代码补全功能,以自动提供允许的常量。
Typedef 注解使用 @interface 来声明新的枚举注解类型。@IntDef 和 @StringDef 注解以及 @Retention 可以对新注解添加注解,是定义枚举类型所必需的。@Retention(RetentionPolicy.SOURCE) 注解可告诉编译器不要将枚举注解数据存储在 .class 文件中。
以下示例展示了创建某个注解的具体步骤,该注解可以确保作为方法参数传递的值引用某个已定义的常量:
import android.support.annotation.IntDef;
//...
public abstract class ActionBar {
//...
// Define the list of accepted constants and declare the NavigationMode annotation
@Retention(RetentionPolicy.SOURCE)
@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
public @interface NavigationMode {}
// Declare the constants
public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;
// Decorate the target methods with the annotation
@NavigationMode
public abstract int getNavigationMode();
// Attach the annotation
public abstract void setNavigationMode(@NavigationMode int mode);
}
构建此代码时,如果 mode 参数未引用任何已定义的常量(NAVIGATION_MODE_STANDARD、NAVIGATION_MODE_LIST 或 NAVIGATION_MODE_TABS),系统会生成一条警告。
您还可以结合使用 @IntDef 和 @IntRange,以指明某个整数可以是一组给定的常量,也可以是某个范围内的值。
支持使用标记将常量组合起来 如果用户可以使用标记(如 |、& 和 ^ 等)将允许的常量组合起来,您可以通过 flag 属性定义一个注解,用于检查参数或返回值是否引用了有效模式。以下示例使用一组有效的 DISPLAY_ 常量来创建 DisplayOptions 注解:
import android.support.annotation.IntDef;
...
@IntDef(flag=true, value={
DISPLAY_USE_LOGO,
DISPLAY_SHOW_HOME,
DISPLAY_HOME_AS_UP,
DISPLAY_SHOW_TITLE,
DISPLAY_SHOW_CUSTOM
})
@Retention(RetentionPolicy.SOURCE)
public @interface DisplayOptions {}
...
限制 API
@RestrictTo 注解用于指明访问添加了此类注解的 API(软件包、类或方法)会受到限制,具体说明如下。
子类 使用 @RestrictTo(RestrictTo.Scope.SUBCLASSES) 注解形式可以仅允许子类访问 API。
只有对添加了此类注解的类进行扩展的类可以访问此 API。Java protected 修饰符的限制性不够严格,因为它允许从同一软件包中的不相关类进行访问。此外,在有些情况下,您会希望使某个方法保持 public 状态,以便将来灵活使用,因为您永远不能使先前处于 protected 状态且被替换的方法变为 public 状态,但您需要提供一条提示,指明该方法应仅在相应类或子类中使用。
库 使用 @RestrictTo(RestrictTo.Scope.GROUP_ID) 注解形式可以仅允许库访问 API。
只有库代码可以访问添加了此类注解的 API。这样,您不仅可以按所需的任何软件包层次结构组织您的代码,还可以在一组相关库之间共享代码。有些支持库包含大量的实现代码,这些代码不适合外部使用,但必须处于 public 状态,以便在各种互补支持库之间共享,而此选项已经可供此类支持库使用。
注意:Android 支持库类和软件包现在带有 @RestrictTo(GROUP_ID) 注解,这意味着,如果您不小心使用了这些实现类,Lint 会警告您不建议这样做。
测试 使用 @RestrictTo(RestrictTo.Scope.TESTS) 注解形式可以防止其他开发者访问您的测试 API。
只有测试代码可以访问添加了此类注解的 API。这样可以防止其他开发者使用您仅打算作测试之用的 API 进行开发。