Android 注解知多少

685 阅读9分钟

Android 注解知多少

前言

作为一个Android开发者来说,ButterKnife和Retrofit都是项目中常用的框架,在运用ButterKnife的时候可以用@BindView()绑定控件,用@OnClick()实现控件的监听器绑定,其实还有@BindBool(),@BindColor(),@BindDimen(),@BindDrawable(),@BindInt(),@BindString()等相关的绑定。在运用Retrofit的时候,运用这种方式来调用api的时候更多,比如@FormUrlEncoded,@POST,@GET,@Multipart等等。其实这些都叫注解,Java在1.5的时候引入了注解的,这样就大大地提高了开发效率。

  • 注解的优点:

  1. 提高开发效率

  2. 能够更早的发现程序的问题或者错误,并提供更加合理的解决方案

  3. 降低维护成本

  4. 无需工具支持,无需解析

  5. 约束开发者的开发规范

  6. 提高代码整洁度

既然Java中能够运用注解来提高效率,那Android当然也可以,其实在Android中sdk已经加入很多提高开发效率的注解。下面就让我们来了解一下Android sdk中的注解。要使用Android sdk中的注解首先得添加Android注解得jar包或者gradle,maven依赖。如果我们引入了appcompat包的话,则不需要引入注解的jar包或者依赖,因为appcom默认引入了注解这个库。

//gradle依赖
dependencies {
    compile 'com.android.support:support-annotations:25.2.0'
}

null相关的注解

其中和null相关的注解分为了@Nullable@NonNull两个,其中前者的含义表示为可为null,后者的含义表示为不能为null,其中@NonNull在代码中检测生效的条件是显示的,不然不生效。显示的意思为明确的传入null或者返回null,这是才会提示警告。

实例:

上图中明显就可以看出标明了@NonNull注解的如果返回值为null就会提是警告,在开发过程中为了代码的安全性和可执行性,一般都会减少警告的数量来完善代码。

区间范围的注解

在Android中如果你想限定一个整形或者浮点型的区间范围的话,就可以使用IntRangeFloatRange注解来标明。

实例:

上面图中展示已经很明确了,如果我们传入了非法的值,就会报错,其实编译运行还是可以的,只是显示的提示你需要修改源代码来提高代码的安全性,规范开发者的行为。

数组大小限制及字符串长度限制

通过使用注解限定数组的大小,如果超出范围则提示错误

实例1:

实例中已经说明得很清楚了,如果通过@Size注解注明大小或者范围的话,在你调用该方法时候如果超出范围就会提示相关错误。

实例2:

字符串和数组如出一辙,使用方法都是如此。但是两者有个缺点就是必须显示调用才会有错误提示,不然是没有错误提示的。并且有错误提示还是不会导致编译失败,上述的注解都是如此,并不能导致编译失败。

替代枚举的使用

Android开发过程中表示一个固定不变值的话一般都会声明一个静态常量值,在使用的地方去引用该静态常量值。然而这种写法有弊端,因为可读性很差,因为你编译打包过后会把这些声明的静态常量名自动替换成相对应的值。也导致你相关数据直接给暴露出来了。

实例1:

这是项目中的源代码

这是这是反编译过后的代码

上面是不是看出结果来了,差别很明显啊,你是引用的一个值为0的常量,而实际上和你直接引用0有啥区别呢。所以有人就会考虑使用枚举不是更好啊,正好避免这种情况。然而枚举在实际情况就是占用很大内存,就因为如此才导致Google曾一度放弃使用枚举。Android既然是Google出的肯定也会考虑这些情况。所以针对Android的一些特殊情况,引入了替代枚举的注解@IntDef@StringDef。此处还是按照实例来说明情况。

此处先贴上枚举的简单使用图

替代枚举的注解使用实例(两者使用的方式相同,此处只列举一个实例)

资源注解相关

上述的注解或许有些人不常用,有些人经常用。还是看团队以及个人的习惯和代码规范。而Android中最常用的注解则是资源的注解使用,相信只要是Android开发者都用过。因为在Android中几乎所有(如assets文件夹下的资源就不是)的资源都可以有对应的资源id。如我们获取定义的字符串。我们可以使用如下方法:

getResources().getString(R.string.app_name);

但是盲目的获取也会带来很多问题,比如说一张图片资源和一个字符串资源都会生成自己独立的id,你本想获取字符串,却用了图片的资源id,这样不用想肯定就会出错的。所以这里就引入了资源注解,通过资源的不同分为了多种不同的资源注解,明明注解标明的资源id为一个字符串,你却使用了一张图片的资源id,就会提示引用资源错误等提示。

资源注解如下:

注解名称 说明
AnimRes 限定为动画的资源id
AnimatorRes 限定为属性动画的资源id
XmlRes 限定为xml资源id
StyleableRes 限定为styleable资源id
TransitionRes 限定为transition动画的资源id
StyleRes 限定为style资源id
StringRes 限定为字符串资源id
RawRes 限定部分不被压缩的资源文件,比如小点的食品,音乐之类的
PluralsRes 限定为plurals类型的资源id
ArrayRes 限定为数组资源id
AnyRes 限定为特殊类型的资源id
AttrRes 限定为AttributeSet资源属性的资源id
BoolRes 限定为Boolean的资源id
ColorRes 限定为颜色资源id
DimenRes 限定为dimen尺寸的资源id
DrawableRes 限定为drawable的资源id
FractionRes 限定为fraction的资源id
IdRes 限定为控件id等的资源id
IntegerRes 限定为整形的资源id
InterpolatorRes 限定为动画资源id
LayoutRes 限定为layout布局的资源id
MenuRes 限定为menu菜单的资源id

上述的很多资源i指向都是非常熟悉的,部分不明确的可以上网查阅资料。

线程相关

Android中提供了四个与线程相关的注解,分别是:

  • @UiThread,通常可以等同于主线程,标注方法需要在UIThread执行,比如View类就使用这个注解

  • @MainThread 主线程,经常启动后创建的第一个线程

  • @WorkerThread 工作者线程,一般为一些后台的线程,比如AsyncTask里面的doInBackground就是这样的.

  • @BinderThread 注解方法必须要在BinderThread线程中执行,一般使用较少.

使用实例(直接在方法上方声明)

注意,这种情况下不会出现错误提示,必须在明确规定下才会提示错误,比如下图所示:

所以只有明确规定线程不同的情况下才会提示错误,不然是不会提示错误的。使用也是如此的简单。

CallSuper注解的使用

该注解的意思为你在重写某方法时,必须调用super方法,在Android中也是很常见并且很常用的,比如说Activity的onSupportActionModeStarted(),onCreate()方法等。

实例

    //父类声明
    @Override
    @CallSuper
    public void onSupportActionModeFinished(@NonNull ActionMode mode) {

    }

    //子类重写
    @Override
    public void onSupportActionModeFinished(@NonNull ActionMode mode) {
        super.onSupportActionModeFinished(mode);//如果注释掉这行会报错,提示必须调用super方法
    }

CheckResult注解的使用

关于检测返回值结果的一个注解,如果得到了结果却没有是用这个结果就会提示错误,一旦出现这种错误,就说明你没有正确使用该方法。如Android中checkPermission这个方法就被标明了该注解。

实例

RequiresPermission权限注解的使用

在Android中如果你的方法的调用需要调用者有特定的权限,你可以使用@RequiresPermission注解:

实例

如果你至少需要权限集合中的一个,你可以使用anyOf属性

@RequiresPermission(anyOf = {Manifest.permission.INTERNET,Manifest.permission.ACCESS_COARSE_LOCATION})

如果你同时需要多个权限,你可以用allOf属性:

@RequiresPermission(allOf = {Manifest.permission.INTERNET,Manifest.permission.ACCESS_COARSE_LOCATION})

RGB颜色值注解@ColorInt

当你需要一个颜色资源是可以使用@ColorRes注解,但是当你需要一个RGB颜色值显然用 @ColorRes注解是不行的,虽然同为整形,但是代表的意思就大不相同了,此时我们想来表示该值为一个RGB颜色值怎么办呢,这时就会用到@ColorInt注解来表示为一个RGB颜色值。

@Keep保持某方法不被混淆的注解

开发过程中一般不会混淆代码,但是到正式打包上线的时候我们需要混淆我们的源代码,方便代码的安全和删除没用的代码来减小包的大小,此时只需要将gradle中的minifyEnabled设置为true就可按照自己项目的混淆规则进行混淆,如果使用注解来保持某方法不被混淆的使用方法也很简单,只需要将注解卸载方法头就OK。

    @Keep
    public String setContent(String content) {
        return content;
    }

总结:

在项目开发过程中使用sdk提供的注解会大大提高编码效率,减小开发时间,不同的注解代表这不同的含义,熟悉其用法,这样提高了代码的整洁度,减少了不必要的判断,限制等条件。ButterKnifeRetrofit相关注解是自定义的注解,后续会更新自定义注解文章,让你在写代码的时候也能合理运用注解这一功能,提高开发效率,提升自己的技能。