首页 > 代码库 > Android提供的常用注解以及自定义注解代替枚举

Android提供的常用注解以及自定义注解代替枚举

尊重他人的劳动成果,转载请标明出处:http://blog.csdn.net/gengqiquan/article/details/70185731, 本文出自:【gengqiquan的博客】

上篇博客嘀咕了注解的基本知识。这篇和大家唠唠Android提供的一些编译限制注解以及怎么自定义贴合自己项目框架的限制注解

Android支持Java默认的那些注解,同时通过一些依赖库也额外提供了很多注解,了解并熟练使用这些注解能够让你的代码更加严谨,结构更加清晰、架构更易维护

Android support library从19.1版本开始引入了一个新的注解库Support Annotations
support appcompa-v7里面默认包含了这个库,如果你没有使用的话也可以通过添加单独依赖的方式引入
在model的build.gradle中添加如下配置:

dependencies {
    compile ‘com.android.support:support-annotations:25.2.0‘
}

选取的25.2.0版本的,包含了如下几种类型的注解

  • 资源引用限制类:用于限制参数必须为对应的资源类型

    AnimRes AnyRes ArrayRes AttrRes BoolRes ColorRes DimenRes DrawableRes FractionRes IdRes IntegerRes InterpolatorRes LayoutRes MenuRes PluralsRes Px RawRes StringRes StyleableRes StyleRes TransitionRes XmlRes

  • 线程执行限制类:用于限制方法或者类必须在指定的线程执行

    AnyThread BinderThread MainThread UiThread WorkerThread

  • 参数为空性限制类:用于限制参数是否可以为空

    NonNull Nullable

  • 类型范围限制类:用于限制标注值的值范围

    FloatRang IntRange

  • 类型定义类:用于限制定义的注解的取值集合

    IntDef StringDef

  • 其他的功能性注解:

    CallSuper CheckResult ColorInt Dimension Keep Px RequiresApi RequiresPermission RestrictTo Size VisibleForTesting

下面分别举例怎么使用

资源引用限制类

用于当我们期望的输入为所注解对应的类型时,可以加上对应的资源类型注解。这样如果输入了非预期类型的资源ID就编译器就会报错,比如我们在写项目框架时定义了一个设置主布局的抽象方法,需要子类继承该类是实现这个方法,返回一个layout布局ID,一般我们会这么写

    public abstract int getLayoutID();

这样这是限制了返回的数据类型必须为int。如果实现该类的人穿了一个drawable的ID或者一个int数值,也是可以正常编译的。要等到运行到该界面时才会报错。这个时候我们就可以用Support Annotations包提供的注解来标注该方法

    @LayoutRes
    public abstract int getLayoutID();

这样当实现该类的人传入一个非layout的ID时编译器就会报except resource of type layout异常 而导致无法编译 。

线程执行限制类

在我们编码的时候,合理的抽取代码为独立的方法是一个很好的习惯,不仅有利于代码的阅读以及相同逻辑的多处调用,也方便后期的重构,同时抽取代码的时候能够让你思考这块逻辑实现是否合理是否过于臃肿。但抽取出来的方法我们有可能放在编写的activity里也可能放在公共类或者变成静态方法,这个时候你不能保证知道调用者会在哪里使用你这段代码。

除非他花时间去仔细阅读你的代码,否则他也不会知道他调用的方法里调用了多少方法,比如方法里包含了一些io操作的代码,或者方法执行特别耗时应该在子线程调用。或者方法里面操作了UI必须在主线程调用。这个时候就可以用线程执行限制类注解在你的方法上,当个调用者并没有再你期望的线程中调用这个方法时编译器就会报错。

需要注意的是这些注解的作用域是类和方法。标注与某个类时表明该类以及内部的所以方法都必须在指定线程调用执行,包括构造方法。
比如MVP中view的接口方法

public interface IBaseView {
    @UiThread
    void showLoading();
    }

加载框必须要在UI线程调用

参数为空性限制类

这个就比较简单了,大家在实现Android的SDK方法的时候经常可以在重写系统方法的时候遇到

NonNull 标注在参数上时编译器会检查参数字段是否可能为空,标记在方法上时会检查返回的值是否为空。可能为空的情况编译器会提示你有一个潜在的崩溃危险

Nullable 标注在参数或有返回值的方法上,表明该参数或方法返回值可以为空

类型限制类

限制参数的数据类型

FloatRange 限定被注解对象必须为float或者double

@Retention(CLASS)
@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE,ANNOTATION_TYPE})
public @interface FloatRange {
    //起始值
    double from() default Double.NEGATIVE_INFINITY;
    //终点值
    double to() default Double.POSITIVE_INFINITY;

    //是否包含起始值
    boolean fromInclusive() default true;

    //是否包含终点值
    boolean toInclusive() default true;
}

IntRange 限定被注解对象必须为int或者long

@Retention(CLASS)
@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE,ANNOTATION_TYPE})
public @interface IntRange {
    //起始值,包含起始值
    long from() default Long.MIN_VALUE;
    //终点值,包含终点值
    long to() default Long.MAX_VALUE;
}

类型定义类

一般用于替代枚举,当我们定义API时,有时候需要传入本地定义好的一些值。为了使这些值具有可读性我们会选择用静态常量,有时候需要限制参数的可取集合。而这些值得类型可能是基础数据类型。为了避免调用API的人传入了其他的不可处理的非预期值进来,我们往往会选择用枚举。而枚举是比较耗费性能的。这个时候我们就可以用注解来替代
比如我们有一个图片上传的API。上传类型需要选择jpg还是png,枚举的方式就是比较简单了。直接定义一个图片类型枚举

public enum  ImgType {
    jpg,png;
}

API

public void  uploadImg(ImgType type) {

}

你现在我们用注解的方式来实现这个需求
我们先定义两个int常量,放入一个常量类Data里

public class   Data {
   public static final int JPG=1000;
   public static final int PNG=1001;
}

然后我们定义一个ImgType注解

@IntDef({Data.JPG,Data.PNG})
@Retention(RetentionPolicy.SOURCE)
public @interface ImgType {

}

这样我们就定义了一个编译时检查的注解,我们把这个注解打在上传图片的API的类型参数上

public void  uploadImg(@ImgType int type) {

}

这样当我们调用API时,一旦我们传入的参数不是Data.JPG或者Data.PNG,编译器就会报错无法通过编译

StringDef用法类似

其他功能类

CallSuper 如果你的API允许使用者重写你的方法,但是你又需要你自己的方法(父方法)在重写的时候也被调用,这时候你可以使用@CallSuper注解

CheckResult 如果你的方法返回一个值,你期望调用者用这个值做些事情,那么你可以使用@CheckResult注解标注这个方法,一般用于那些返回值被使用才有意义的API

ColorInt 当你期望传递的是一个真实的RGB或者ARGB的颜色值而不是颜色资源ID的时候可以使用该注解来提示API调用者

Dimension 标注的对象或者方法必须提供一个int的值,就是Android的屏幕上描述距离的一种单位

Keep 启用混淆的时候告诉编译器被注解的对象不要混淆

Px 标注的对象或者方法必须提供一个int的值,pixel

RequiresApi 当你提供的API是基于某个SDK版本开发的,要求调用者必须处理好低SDK版本兼容操作的时候,或者告诉调用者你的API只能在某个版本的SDK之后才可以正常的工作

RequiresPermission 告诉调用你API的人你的API需要特定的权限
如果你至少需要权限集合中的一个,你可以使用anyOf属性

@RequiresPermission(anyOf = {
    Manifest.permission.INTERNET,
    Manifest.permission.READ_PHONE_STATE})
public abstract string getSaveUser();

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

@RequiresPermission(allOf = {
    Manifest.permission.READ_PHONE_STATE,
    Manifest.permission.READ_PHONE_STATE})
public abstract string getSaveUser();

RestrictTo 注解的对象只接受一个特定范围的值,值范围是一个枚举

Size 限制一个列表集合的大小

@Retention(CLASS)
@Target({PARAMETER,LOCAL_VARIABLE,METHOD,FIELD,ANNOTATION_TYPE})
public @interface Size {
    //该注解必须要给一个值,默认-1
    long value() default -1;
    //最小的大小
    long min() default Long.MIN_VALUE;
   // 最大的大小
    long max() default Long.MAX_VALUE;
    //大小必须为这个值的倍数,默认为1
    long multiple() default 1;
}

VisibleForTesting 这个注解作用的对象测试的时候可以直接调用

以上就是Support Annotations提供的注解的用法了,由于篇幅问题,下一篇我们在聊怎么定义以及代码解析运行时注解

有什么建议的可以留言喔

如果我的博客对您有帮助,请留言鼓励下或者点个赞吧!

我建了一个QQ群(群号:121606151),用于大家讨论交流Android技术问题,有兴趣的可以加下,大家一起进步。

<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    Android提供的常用注解以及自定义注解代替枚举