在浏览Butter Knife源码时,发现里面用了好几个support包里的注解,比如@UiThread
;当时一脸懵逼,第一次见到。再学习过后,今天,介绍下support包的注解。注解可以简化代码并提高编码的效率,所以熟练使用support包里的注解还是很有必要的。
对注解还不太了解的盆友,可以看看这篇博客深入理解Java注解类型
@Nullable
和@NonNull
这两个注解都是标记注释,没有特定的属性。
@Nullable
用在参数,字段或方法的返回值上,表示可以为null;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHitMvpPresenter.attachView(this);
initPresenter(mHitMvpPresenter);
mMovieListAdapter.setBaseFragment(this);
}
在Fragment
的onCreate()
中,@Nullable
用在savedInstanceState
上表示可以传入null进去。
@NonNull
用在参数,字段或方法返回值上,表示不能为空。
在调用某个方法时,方法参数上有@Nullable
,就表示可以给个null,而不必担心空指针;方法参数上有@NonNull
,就表示不可以给null,否则会出现空指针。这样就可以提高编码效率,避免不必要的错误。
资源注解也都是标记注释,没有特定的属性。
@AnimatorRes
用在整数参数、字段或方法返回值上,表示动画资源
@AnimRes
用在整数参数、字段或方法的返回值上,表示anim资源
@AnyRes
用在整型参数、字段或方法返回值上,表示任何类型的资源
@ArrayRes
用在整数参数,字段或方法的返回值上,表示数组资源
@AttrRes
用在整数参数,字段或方法的返回值上,表示属性资源(R.attr.height
)
@BoolRes
用在整数参数,字段或方法的返回值上,表示布尔资源
@ColorRes
用在整数参数,字段或方法的返回值上,表示颜色资源
@DimenRes
用在整数参数,字段或方法的返回值上,表示dimen资源(R.dimen.bar_height
)
@DrawableRes
用在整数参数,字段或方法的返回值上,表示drawable资源
@FontRes
用在整数参数,字段或方法的返回值上,表示字体资源(R.font.myfont
)
@FractionRes
用在整数参数,字段或方法的返回值上,表示百分数资源(R.fraction.test
)
@IdRes
用在整数参数,字段或方法的返回值上,表示id资源(R.id.button
)
@IntegerRes
用在整数参数,字段或方法的返回值上,表示integer资源(android.R.integer.config_shortAnimTime
)
@InterpolatorRes
用在整数参数,字段或方法的返回值上,表示插值器资源(android.R.interpolator.cycle
)。
@LayoutRes
用在整数参数,字段或方法的返回值上,表示布局文件资源
@MenuRes
用在整数参数,字段或方法的返回值上,表示菜单资源
@NavigationRes
用在整数参数,字段或方法的返回值上,表示导航资源(R.navigation.flow
)
@PluralsRes
用在整数参数,字段或方法的返回值上,表示plurals资源(复数形式的字符串,具体可以参考这篇博客)
@RawRes
用在整数参数,字段或方法的返回值上,表示raw资源
@StringRes
用在整数参数,字段或方法的返回值上,表示字符串资源
@StyleableRes
用在整数参数,字段或方法的返回值上,表示自定义属性资源(android.R.styleable.TextView_text
)
@StyleRes
用在整数参数,字段或方法的返回值上,表示样式资源
@TransitionRes
用在整数参数,字段或方法的返回值上,表示过渡资源(Activity之间切换时的过渡动画)
@XmlRes
用在整数参数,字段或方法的返回值上,表示xml资源
用的最多的就是@StringRes
、@ColorRes
、@DimenRes
、@IdRes
、@DrawableRes
;以@DrawableRes
为例
public void setBackground(int id){
imageView.setBackgroundResource(id);
}
public void setBackgroundRes(@DrawableRes int id){
imageView.setBackgroundResource(id);
}
给这两个方法都传入非drawable资源id,比如0;编译的时候,setBackgroundRes()
就会报错;而setBackground()
能编译通过,但是在运行的时候程序就会崩溃。setBackground()
发现错误比setBackgroundRes()
晚,如果setBackground()
也用@DrawableRes
的话,就可以在编译阶段发现错误。在这例子中,资源注解就是帮助编译器在编译阶段检查方法参数是否是资源id。
@FloatRange
、@IntRange
、@Size
、@ColorInt
、@ColorLong
、@HalfFloat
、@Dimension
、@Px
@IntRange
表示元素在给定的int或long范围内
@Retention(CLASS)
@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE,ANNOTATION_TYPE})
public @interface IntRange {
/** Smallest value, inclusive */
long from() default Long.MIN_VALUE;
/** Largest value, inclusive */
long to() default Long.MAX_VALUE;
}
当不知道一个注解可以用在什么元素上时,可以点开它;看看它的@Target内容。在这,@IntRange
可以用在方法、方法参数、字段、局部变量、注解上。当未指定Target值时,此注解就可以用于任何元素之上。
有两个属性,而且都有默认值。
public void setColor(@IntRange(from=0,to=255) int color) {
.....
}
@FloatRange
表示元素在给定的float或double范围内,用法与@IntRange
一样。
@Retention(CLASS)
@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE,ANNOTATION_TYPE})
public @interface FloatRange {
/** Smallest value. Whether it is inclusive or not is determined
* by {@link #fromInclusive} */
double from() default Double.NEGATIVE_INFINITY;
/** Largest value. Whether it is inclusive or not is determined
* by {@link #toInclusive} */
double to() default Double.POSITIVE_INFINITY;
/** Whether the from value is included in the range */
boolean fromInclusive() default true;
/** Whether the to value is included in the range */
boolean toInclusive() default true;
}
比@IntRange
多了两个方法;fromInclusive()
表示是否包含from值,默认是包含的;toInclusive()
表示是否包含to值,默认是包含的。@FloatRange
可以通过这两个方法来控制是否包含from值与to值;而@IntRange
是默认包含的,不能改变。
@Size
表示元素具有的给定的大小或长度。
@Retention(CLASS)
@Target({PARAMETER,LOCAL_VARIABLE,METHOD,FIELD,ANNOTATION_TYPE})
public @interface Size {
/** An exact size (or -1 if not specified) */
long value() default -1;
/** A minimum size, inclusive */
long min() default Long.MIN_VALUE;
/** A maximum size, inclusive */
long max() default Long.MAX_VALUE;
/** The size must be a multiple of this factor */
long multiple() default 1;
}
min()表示最小的大小( @Size(min=1))
max()表示最大的大小(@Size(max=5))
value()表示确定的大小(@Size(value=3)或@Size(3))
multiple()表示大小必须为此数字的倍数(@Size(multiple=2))
@ColorInt
表示元素为颜色的int值,以Color类文件中BLACK的声明为例。
@ColorInt public static final int BLACK = 0xFF000000;
@ColorLong
表示元素为颜色的long值,@ColorInt
比它更常用一些。
@HalfFloat
表示元素为半精度浮点数。(半精度浮点数是IEEE754标准的浮点数类型之一,精度为0.001,占2字节空间;适用于对精度要求不高,但对存储空间要求很高的场合)。比如在Color类文件中的pack()
就用到了该注解。
@ColorLong
public static long pack(float red, float green, float blue, float alpha,@NonNull ColorSpace colorSpace) {
..........
@HalfFloat short r = Half.toHalf(red);
@HalfFloat short g = Half.toHalf(green);
@HalfFloat short b = Half.toHalf(blue);
..........
}
@Dimension
表示整数参数,字段或方法的返回值是尺寸大小。
@Documented
@Retention(CLASS)
@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE,ANNOTATION_TYPE})
public @interface Dimension {
@DimensionUnit
int unit() default PX;
int DP = 0;
int PX = 1;
int SP = 2;
}
默认的单位是像素,可以通过unit()
来修改。(@Dimension(uint=Dimension.DP)
)
@Px
表示整数参数,字段或方法返回值是像素大小。
@Documented
@Retention(CLASS)
@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
@Dimension(unit = Dimension.PX)
public @interface Px {
}
@Dimension
是可以用在注解声明上的,所以你也可以模仿@Px
,自定义一个表示字体大小的注解。
@Documented
@Retention(CLASS)
@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
@Dimension(unit = Dimension.SP)
public @interface Sp {
}
@RequiresApi
与@RequiresPermission
@RequiresApi
表示元素只应在给定的API级别或更高级别上调用。
@RequiresPermission
表示元素需要(或可能需要)一个或多个权限。
@Retention(CLASS)
@Target({ANNOTATION_TYPE,METHOD,CONSTRUCTOR,FIELD,PARAMETER})
public @interface RequiresPermission {
String value() default "";
String[] allOf() default {};
String[] anyOf() default {};
boolean conditional() default false;
@Target({FIELD, METHOD, PARAMETER})
@interface Read {
RequiresPermission value() default @RequiresPermission;
}
@Target({FIELD, METHOD, PARAMETER})
@interface Write {
RequiresPermission value() default @RequiresPermission;
}
}
value()
表示只需要一个权限
allOf()
表示需要多个权限
anyOf()
表示至少需要一个权限
conditional()
默认为false;如果为true,表示在某些情况下,可能不需要权限。
@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");
@AnyThread
表示元素可以被任何线程都调用
@BinderThread
表示元素只能被Binder线程都调用
@MainThread
表示元素只能被Main线程都调用
@WorkerThread
表示元素只能被后台线程都调用
@UiThread
表示元素只能被Ui线程都调用
构建工具会将
@MainThread
和@UiThread
注解视为可互换,因此,可以从@MainThread
方法调用@UiThread
方法,反之也一样。但是,MainThread
与UiThread
是有区别的;最好还是用@UiThread
标注与应用的视图层次结构关联的方法,用@MainThread
标注与应用生命周期关联的方法。
线程注解仅仅是提示编程者注解元素应该在那个线程里调用;在程序编译的时候,编译器没有检查注解元素是否在正确的线程里调用。比如下图中的用法,编译正常通过了,也没有警告或错误。
@IntDef
与@StringDef
都只能用在注解的声明上,它们的作用类似于枚举,以@IntDef
为例。
@Retention(RetentionPolicy.SOURCE)
@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
public @interface NavigationMode {}
public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;
@NavigationMode
public abstract int getNavigationMode();
public abstract void setNavigationMode(@NavigationMode int mode);
再调用setNavigationMode()
时,其参数只能是上面这三个常量之一。
@CallSuper
只用在方法上,表示任何重写该方法的子类,也应该调用该方法。
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
.......
}
如果注释掉super.onCreate(savedInstanceState);
,就会出现下图中的情况。
编辑器是怎么知道的,就是因为@CallSuper
;Activity的onCreate()
用到了这个注解。
@CheckResult
用来验证是否使用了方法返回值,可以通过添加注释来进行提示。
@GuardedBy
表示仅当持有了引用锁时,才能访问注释的方法或字段。
final Object objectLock = new Object();
@GuardedBy("objectLock")
volatile Object object;
Object getObject() {
synchronized (objectLock) {
if (object == null) {
object = new Object();
}
}
return object;
}
@Keep
用在包、类、注解、构造器、方法、字段上,表示在删除无用代码(应该就是代码混淆)时,会保留用了该注解的元素。
@RestrictTo
表示元素只应在特定范围内(RestrictTo.Scope
)使用,具体参考官方文档。
@VisibleForTesting
表示一个代码块的可见性是否高于让代码变得可测试所需要的水平,具体参考官方文档