Android 常用注解
Nullness 注解
-
@Nullable
注解指示可以为 null 的变量、参数或返回值。 -
@NonNull
则指示不可为 null 的变量、参数或返回值。
资源注解
-
@StringRes
注解,以检查资源参数是否包含R.string
引用,其他资源类型的注解@DrawableRes
、@DimenRes
、@ColorRes
和@InterpolatorRes
,使用@AnyRes
能够指示注解的参数可为任意类型的 R 资源。
尽管您可以使用 @ColorRes 指定某个参数应为颜色资源,但是颜色整型(RRGGBB 或 AARRGGBB 格式)无法识别为颜色资源。请改用 @ColorInt 注解指示某个参数必须为颜色整型。构建工具会标记不正确代码,该代码会将颜色资源 ID(例如 android.R.color.black)而不是颜色整型传递到已注解方法。
常见的Resource Type注解,使用方式都是指定一个integer的参数、成员变量、或者方法,检查对应的资源类型。
-
AnimatorRes
:animator资源类型 -
AnimRes
:anim资源类型 -
AnyRes
:任意资源类型 -
ArrayRes
:array资源类型 -
AttrRes
:attr资源类型 -
BoolRes
:boolean资源类型 -
ColorRes
:color资源类型 -
DimenRes
:dimen资源类型。 -
DrawableRes
:drawable资源类型。 -
FractionRes
:fraction资源类型 -
IdRes
:id资源类型 -
IntegerRes
:integer资源类型 -
InterpolatorRes
:interpolator资源类型 -
LayoutRes
:layout资源类型 -
MenuRes
:menu资源类型 -
PluralsRes
:plurals资源类型 -
RawRes
:raw资源类型 -
StringRes
:string资源类型 -
StyleableRes
:styleable资源类型 -
StyleRes
:style资源类型 -
TransitionRes
:transition资源类型 -
XmlRes
:xml资源类型
以上基本上包括了所有的资源类型,但是有时需要通过RGB颜色整型来设置颜色值,在这种情况下,你可以使用@ColorInt
注解,表示你期望的是一个代表颜色的整数值,如果使用不对同样也是编译不通过
线程注解
线程注解可以检查某个方法是否从特定类型的线程调用。支持以下线程注解:
@MainThread
@UiThread
@WorkerThread
@BinderThread
@AnyThread
注:构建工具会将 @MainThread 和 @UiThread 注解视为可互换,因此,您可以从 @MainThread 方法调用 @UiThread 方法,反之亦然。不过,如果系统应用在不同线程上带有多个视图,UI 线程可与主线程不同。因此,您应使用 @UiThread 标注与应用的视图层次结构关联的方法,使用 @MainThread 仅标注与应用生命周期关联的方法。
值约束注解
使用 @IntRange
、@FloatRange
和 @Size
注解可以验证传递的参数的值。在应用到用户可能弄错其范围的参数时,@IntRange
和 @FloatRange
都非常有用。
@IntRange
注解可以验证整型或长整型参数值是否位于指定范围内。下面的示例可以确保 alpha 参数包含 0 至 255 范围内的整数值:
public void setAlpha(@IntRange(from=0, to=255) int alpha) {...}
@FloatRange
注解可以检查浮点或双整型参数值是否位于指定的浮点值范围内。下面的示例可以确保 alpha 参数包含 0.0 至 1.0 的浮点值:
public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {...}
@Size
注解可以检查集合或数组的大小,以及字符串的长度。@Size
注解可用于验证以下质量:
最小大小(例如 @Size(min=2)
)
最大大小(例如 @Size(max=2)
)
确切大小(例如 @Size(2)
)
表示大小必须为此倍数的数字(例如 @Size(multiple=2)
)
例如,@Size(min=1)
可以检查某个集合是否不为空,@Size(3)
可以验证某个数组是否刚好包含三个值。下面的示例可以确保 location 数组至少包含一个元素:
int[] location = new int[3];
button.getLocationOnScreen(@Size(min=1) location);
权限注解
使用 @RequiresPermission
注解可以验证方法调用方的权限。要检查有效权限列表中是否存在某个权限,请使用 anyOf
属性。要检查是否存在一组权限,请使用 allOf
属性。下面的示例会标注 setWallpaper() 方法,以确保方法的调用方拥有 permission.SET_WALLPAPERS 权限:
@RequiresPermission(Manifest.permission.SET_WALLPAPER)
public abstract void setWallpaper(Bitmap bitmap) throws IOException;
此示例要求 copyFile() 方法的调用方同时具有外部存储空间的读写权限:
@RequiresPermission(allOf = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE})
public static final void copyFile(String dest, String source) {
...
}
对于 intent 权限,请将权限要求添加到定义 intent 操作名称的字符串字段上:
@RequiresPermission(android.Manifest.permission.BLUETOOTH)
public static final String ACTION_REQUEST_DISCOVERABLE =
"android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
对于您需要单独读写权限的内容提供程序的权限,请在 @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) {...}
在您使用间接权限时,构建工具将执行数据流分析以检查传递到方法的参数是否具有任何 @RequiresPermission
注解。随后,它们会对方法本身强制参数的任何现有注解。在 startActivity(Intent)
示例中,当一个不具有相应权限的 intent 传递到方法时,Intent 类中的注解会针对 startActivity(Intent)
的无效使用生成警告,如图 1 中所示。
图 1. startActivity(Intent) 方法上从间接权限注解生成的警告。
构建工具会在 startActivity(Intent)
上从 Intent 类中相应 intent 操作名称的注解生成警告:
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@RequiresPermission(Manifest.permission.CALL_PHONE)
public static final String ACTION_CALL = "android.intent.action.CALL";
如果需要,在标注方法的参数时,您可以将 @RequiresPermission
替换为 @RequiresPermission.Read
和/或 @RequiresPermission.Write
。不过,间接权限 @RequiresPermission 不应与读取或写入权限注解搭配使用。
返回值注解
使用 @CheckResult
注解可以验证实际使用的是方法的结果还是返回值。添加注释来阐明可能令人困惑的方法的结果,而不是使用 @CheckResult
标注每个非空方法。例如,新 Java 开发者经常误认为 <String>.trim() 会移除原始字符串中的空格。使用 @CheckResult
标注方法会在调用方未对方法返回值作任何处理的地方标记 <String>.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) {
}
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
注解:
@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 {}
在您使用注解标志构建代码时,如果经过修饰的参数或返回值不引用有效模式,则将生成警告。
代码可访问性注解
使用 @VisibleForTesting
和 @Keep
注解可以表示方法、类或字段的可访问性。
@VisibleForTesting
注解指示一个代码块的可见性是否高于让代码变得可测试所需要的水平。
@Keep
注解可以确保如果在构建时缩减代码,标注的元素不会移除。它一般会添加到通过反射访问的方法和类中,以阻止编译器将代码视为未使用。