天天看点

Android注解:Android 常用注解1 添加支持注解库依赖项2 运行代码检查3 Android常用注解

Android注解:Android 常用注解

  • 1 添加支持注解库依赖项
  • 2 运行代码检查
  • 3 Android常用注解
    • 3.1 Nullness 注解
      • 3.1.1 Nullness 分析
    • 3.2资源注解
    • 3.3 线程注解
    • 3.4 值约束注解
    • 3.5 权限注解
      • 间接权限
    • 3.6 CallSuper 注解
    • 3.7 Typedef 注解
      • 允许将常量与标志相结合
    • 3.8 可访问性注解

首先说一下在Android代码中使用注解的好处。使用注解向 Lint 之类的代码检查工具提供提示,帮助检测这些更细微的代码问题;还可以少写一些重复代码;使用注解还非常的方便等等。

1 添加支持注解库依赖项

支持注解库是 Android 支持库的一部分。要向您的项目添加注解,您必须下载支持存储库并向 build.gradle 文件中添加 support-annotations 依赖项。

  • 打开 SDK 管理器,方法是点击工具栏中的 SDK Manager 或者选择 Tools > Android > SDK Manager。

    点击 SDK Tools 标签。

    展开 Support Repository 并选中 Android Support Repository 复选框。

    点击 OK。

    继续安装向导的说明操作,安装软件包。

  • 将以下代码行添加到 build.gradle 文件的 dependencies 块中,向您的项目添加 support-annotations 依赖项:

    dependencies { compile 'com.android.support:support-annotations:24.2.0' }

如果下载的库版本可能较高,因此,确保在此指定的值与第 3 步中的版本匹配。

在显示的工具栏或同步通知中,点击 Sync Now。

2 运行代码检查

要从 Android Studio 启动代码检查(包含验证注解和自动 Lint 检查),请从菜单栏中选择 Analyze > Inspect Code。Android Studio 将显示冲突消息,在您的代码与注解冲突的地方标记潜在问题并建议可能的解决方法。

3 Android常用注解

3.1 Nullness 注解

Nullness注解包括

@Nullable @NonNull

注解,以检查变量、参数或者返回值的nullness。

@Nullness

表示可以为null;

@NonNull

表示不可以为null

通过

@Nullable

标记的方法,如果使用其返回值不进行null的检查,则会出现警告。

@Nullable
public TextView getTextView(){
    return new TextView(this);
}
//使用
getTextView().setVisibility(View.VISIBLE);
           

在Android Studio中会报警告:Method invocation “setVisibility” may produce ‘java.lang.NullPointerException’…

3.1.1 Nullness 分析

Android Studio 支持通过运行 nullability分析,在您的代码中自动推断和插入 nullness注解。Nullability分析会在您代码的整个方法层次结构中扫描协定类,以检测:

  • 可返回 Null 的调用方法
  • 不会返回 Null 的方法
  • 可以为 Null 的变量,如字段、局部变量和参数
  • 不能为 Null 值的变量,如字段、局部变量和参数

然后,此分析将自动在已检测到的位置插入相应的 null 注解。

要在 Android Studio 中运行 nullability 分析,请选择 Analyze > Infer Nullity。Android Studio 会在代码中已检测到的位置插入 Android @Nullable 和 @NonNull 注解。运行 null 分析后,最好验证一下插入的这些注解。

3.2资源注解

验证资源类型可能非常有用,因为Android对资源(例如可绘制对象和字符串资源)的引用以整型形式传递。需要参数来引用特定类型资源(例如可绘制对象)的代码可以作为预计的引用类型 int 传入,不过实际将引用不同类型的资源,例如 R.string 资源。

例如,添加 @StringRes 注解,以检查资源参数是否包含 R.string 引用,如下面所示:

在代码检查期间,如果参数中未传入 R.string 引用,注解将生成警告。

常见的资源注解:

@IntegerRes:R.integer 类型资源。

@AnimatorRes:R.animator 类型资源。

@AnimRes:R.anim 类型资源。

@ArrayRes:R.array 类型资源。

@AttrRes:R.attr 类型资源。

@BoolRes:R.bool 类型资源。

@ColorRes:R.color 类型资源。

@DimenRes:R.dimen 类型资源。

@DrawableRes:R.drawable 类型资源。

@FractionRes:R.fraction 类型资源。(百分比)

@IdRes:R.id 类型资源。

@InterpolatorRes:R.interpolator 类型资源。(插值器)

@LayoutRes:R.layout 类型资源。

@MenuRes:R.menu 类型资源。

@PluralsRes:R.plurals 类型资源。(复数)

@RawRes:R.raw 类型资源。

@StyleableRes:R.styleable 类型资源。

@StyleRes:R.style 类型资源。

@TransitionRes: R.transition 类型资源。

@XmlRes:R.xml 类型资源。

@AnyRes:未知资源。(表示自己不知道是什么类型的资源。比如有可能为 R.drawable 也有可能是 R.string。)

可以使用相同的注解格式添加并在代码检查期间运行。如果您的参数支持多种资源类型,您可以在给定参数上添加更多注解。

@AnyRes 能够指示注解的参数可为任意类型的 R 资源。

@ColorRes 与@ColorInt

尽管您可以使用 @ColorRes 指定某个参数应为颜色资源,但是颜色整型(RRGGBB 或 AARRGGBB 格式)无法识别为颜色资源。请改用 @ColorInt 注解指示某个参数必须为颜色整型。构建工具会标记不正确代码,该代码会将颜色资源 ID(例如 android.R.color.black)而不是颜色整型传递到已注解方法。

3.3 线程注解

线程注解可以检查某个方法是否从特定类型的线程调用。支持以下线程注解

  • @MainThread
  • @UiThread
  • @WorkerThread
  • @BinderThread
  • @AnyThread

注:1、构建工具会将 @MainThread 和 @UiThread 注解视为可互换,因此,您可以从 @MainThread 方法调用 @UiThread 方法,反之亦然。不过,如果系统应用在不同线程上带有多个视图,UI 线程可与主线程不同。因此,您应使用 @UiThread 标注与应用的视图层次结构关联的方法,使用 @MainThread 仅标注与应用生命周期关联的方法。

2、WorkerThread 表示标记的方法只应该在工作线程上调用。如果标记的是一个类,那么该类中的所有方法都应是在一个工作线程上调用

3、BinderThread 表示标记的方法只应在绑定线程上调用。如果标记的是一个类,那么该类中的所有方法都应是在绑定线程被调用

3.4 值约束注解

使用 @IntRange、@FloatRange 和 @Size 注解可以验证传递的参数的值。在应用到用户可能弄错其范围的参数时,@IntRange 和 @FloatRange 都非常有用。

例:

public void setAlpha(@IntRange(from=0,to=255) int alpha) { … }
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))

int[] location = new int[3];
button.getLocationOnScreen(@Size(min=1) location);
           

3.5 权限注解

使用 @RequiresPermission 注解可以验证方法调用方的权限。

@RequiresPermission(Manifest.permission.SET_WALLPAPER)
public abstract void setWallpaper(Bitmap bitmap) throws IOException;

@RequiresPermission(allOf = {
    Manifest.permission.READ_EXTERNAL_STORAGE,
    Manifest.permission.WRITE_EXTERNAL_STORAGE})
public static final void copyFile(String dest, String source) {
    ...
}
           

要检查有效权限列表中是否存在某个权限,请使用 anyOf 属性。要检查是否存在一组权限,请使用 allOf 属性。上面的示例会标注 setWallpaper() 方法,以确保方法的调用方拥有 permission.SET_WALLPAPERS 权限;

要求 copyFile() 方法的调用方同时具有外部存储空间的读写权限

对于 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 使用间接权限:

在您使用间接权限时,构建工具将执行数据流分析以检查传递到方法的参数是否具有任何 @RequiresPermission 注解。随后,它们会对方法本身强制参数的任何现有注解。在 startActivity(Intent) 示例中,当一个不具有相应权限的 intent 传递到方法时,Intent 类中的注解会针对 startActivity(Intent) 的无效使用生成警告,如图 1 中所示。

Android注解:Android 常用注解1 添加支持注解库依赖项2 运行代码检查3 Android常用注解

图 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 不应与读取或写入权限注解搭配使用。

3.6 CallSuper 注解

使用 @CallSuper 注解可以验证替换方法是否会调用方法的超类实现。下面的示例会标注 onCreate() 方法,以确保任何替换方法实现都会调用 super.onCreate():

@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}
           

3.7 Typedef 注解

使用 @IntDef 和 @StringDef注解,能够创建整型和字符串集的 枚举 注解来验证其他类型的代码引用。

Typedef 注解可以确保特定参数、返回值或字段引用特定的常量集。它们还可以完成代码以自动提供允许的常量。

下面的示例说明了创建注解的具体步骤,此注解可以确保作为方法参数传递的值引用一个定义的常量:

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;
...
public static final int DISPLAY_USE_LOGO = 1;
public static final int DISPLAY_SHOW_HOME = 2;
public static final int DISPLAY_HOME_AS_UP= 4;
public static final int DISPLAY_SHOW_TITLE= 8;
public static final int DISPLAY_SHOW_CUSTOM =16;
@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 {}
//使用
@DisplayOptions int a= DISPLAY_USE_LOGO;
@DisplayOptions int b= DISPLAY_SHOW_HOME;
@DisplayOptions int c= a|b;
           

在您使用注解标志构建代码时,如果经过修饰的参数或返回值不引用有效模式,则将生成警告。

3.8 可访问性注解

使用 @VisibleForTesting 和 @Keep 注解可以表示方法、类或字段的可访问性。

@VisibleForTesting 注解指示一个代码块的可见性是否高于让代码变得可测试所需要的水平。

@Keep 注解可以确保标记的指定代码在混淆时不会被混淆。它一般会添加到通过反射访问的方法和类中,以阻止编译器将代码视为未使用。

参考资料:

  1. Android官方注解
  2. Android 中注解的使用