概述

Java语言提供了Annotation的机制,让描述性的元数据能够和代码共存。通常我们可以利用Annotation,来做一些标志性的说明。然而Annotation必须和相应的解析工具一起才能工作。合理的运用Annotation,会带来一些额外的效果。

本文不讨论Annotation的基础语法以及基础使用方法。

Android用Annotation干了什么?

Java这种强类型的语言,在编写代码的时候,编辑器就会通过语法检查,来阻止一些错误的发生。相比于一些弱类型的语言,更安全。Annotation作为元数据而存在,结合上运行在编辑期的解析工具,可以做到更细致的代码检查,可以说是一种对语法检查的扩充吧。

Android就充分利用了这一点,Android在提供了大量的Annotation的同时,也在ADT中提供了操作这些Annotation的工具,主要体现在代码检查阶段。下面我们会详细看一下Android提供的Annotation。这些Annotation不仅可以让代码在编写的时候,少出一些问题,而且可以对一个类、方法等做详细的说明。这些Annotation也可以指导使用API的开发人员,正确的使用API。

Android是如何运用Annotation来进行代码检查的?

Android提供了几大类的Annotation,用来配合其相应的解析工具,来对代码做更严格的检查。

1、强制方法调用类型。

作用:指示所有Override该方法的方法,都需要调用调用该方法。

Annotations:@CallSuper

使用场景:你设计了一个框架,里面有一些基础方法,各子类需要覆写该方法,但是一定要调用父类的方法。这时候可以使用这个Annotation来强制子类调用父类的方法。

        示例代码:

    //父类
@CallSuper
protected void fun() {
System.out.println("parent fun()");
} //子类
@Override
protected void fun() {
super.fun();
}

如果不调用 super.fun(),则会出现提示:Overriding method should call super.fun。

2、指定固定常量型。

作用:指示一个逻辑类型,并且这个逻辑类型的值只能取固定的常量。

Annotations:@IntDef

@StringDef

使用场景:作为一个特定类型的有限个取值,可以使用Enum或者使用常量,但是Enum可以有类型检查,而常量没有。众所周知,因为内存占用的问题,Android不推荐使用Enum,那就只能使用常量,但是常量不能做类型检查,所以Android就提供了这样一种方法,来解决此问题,让指定的属性值只能取定义好的常量。

        示例代码:

    //定义常量
public static final int INT_1 = 1;
public static final int INT_2 = 2; //指定该Annotation描述的对象,只能使用这两个常量
@IntDef({INT_1, INT_2})
public @interface MyType {
} //如果一个方法只想接收这两个常量(常量名称,而不是常量的值)作为参数,那么可以这样使用
private void f (@MyType int time) {
}

如果调用f()时,不传递这两个常量,比如f(2)。那么就会报错:Must be one of: INT_1, INT_2。

3、资源对象的值类型指定型。

作用:指示所描述的参数、字段、返回值必须是指定的资源类型的引用。

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

使用场景:如果你有一个方法,需要一个 R.id 的值作为参数,或者一个方法,希望返回值是 R.anim
类型的引用,那么这个时候就可以使用这些Annotation。

        示例代码:

    //希望接收一个id作为参数
private void f (@IdRes int id) {
} private void call() {
//但是实际上不小心传递了一个layout进去。
f(R.layout.day_view);
}

那么这个时候就会报错:Expected resource of type id。

4、取值范围型。

作用:指示一个int、float或者double类型的值,合理的取值范围。

Annotations:@FloatRange

@IntRange

使用场景:比如有一个方法,接收一个int型的透明度参数,那么该方法就会希望传进来的值应该是0~255,这时就可以使用该Annotation。

        示例代码:

    //希望接收一个[0, 255]的值作为透明度
private void setAlpha (@IntRange(from = 0, to = 255) int alpha) {
} private void call() {
//但是实际上不小心传递了一个300进去。
setAlpha(300);
}

那么这个时候就会报错:Value must be ≥ 0 and ≤ 255 (was 300)。

5、线程标识型。

作用:指示某个对象、构造器或者方法,应该在指定的类型的线程运行。

Annotations:@BinderThread

@MainThread

@UiThread

@WorkerThread

使用场景:如果有一个方法,比较耗时,所以它应该放在工作线程执行。这时候可以用@WorkerThread来标注该方法,当在主线程调用该方法的时候,就会报错。

示例代码:

    //该方法比较耗时,所以放在子线程执行
@WorkerThread
private void shouldRunOnWorkerThread() {
} @MainThread
private void runOnMainThread() {
//在主线程调用该方法,会报错。
shouldRunOnWorkerThread();
}

那么这个时候就会报错:Method shouldRunOnWorkerThread must be called from the worker thread, currently inferred thread is main。

像 Activity 的onCreate方法,都是被标注为主线程执行的。

    @MainThread
@CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState) {
.......................;
}

6、空指针指示型。

作用:指示某个参数、返回值等是否可以为空。

Annotations:@NonNull

@Nullable

使用场景:比如一个方法,可能返回一个null,可以使用@Nullable来标注,那么使用该方法的地方,一般都要做null判断。

7、混淆指示类型。

作用:指示被描述的对象,在编译的时候不要被混淆。

Annotations:@Keep

使用场景:当一个方法、属性、对象等,需要被反射使用时,比如通过反射来实现工厂。这时候可以使用该Annotation来标记,这样在编译的时候,就不会被混淆(如果开了混淆的话)。

        示例代码:

//抽象产品,避免被混淆
@Keep
class Product {} //产品A,避免被混淆
@Keep
class ProductA extends Product{} //产品B,避免被混淆
@Keep
class ProductB extends Product{} private Product getProduct(String productName) {
//使用反射创建具体的Product
return ...;
}

8、参数长度限定类型。

作用:指示被描述的对象应该有明确的大小。

Annotations:@Size

使用场景:当一个参数,需要最小的大小时,使用该Annotation,比如,一个数组最少有2个元素、一个String最低长度为3等。

        示例代码:

    //要求param的长度最小为2
private void minSize(@Size(min = 2) String param) {
} private void callMinSize() {
//传递长度只有1的"s"时,会报错
minSize("s");
}

那么这个时候就会报错:Length must be at least 2 (was 1)。

9、其他类型。

作用:指示一个int值是颜色类型的值(AARRGGBB)。

Annotations:@ColorInt

        示例代码:

    //标明该常量代表颜色值
@ColorInt public static final int BLACK = 0xFF000000;
//标明该方法希望接收一个代表颜色值的参数
public setColor(@ColorInt int color) {
}

合理使用Android提供的Annotation来提高代码的质量的更多相关文章

  1. Android 你可能忽略的提高敲代码效率的方式 (转)

    每日推荐 Eyepetizer-in-Kotlin:一款简约的小视频app,带你走进kotlin 作为学习kotlin的一款app,在撸代码的过程中学习kotlin的语法及特性. Eyepetizer ...

  2. Android 命名规范 (提高代码可以读性)

    android文件众多,根据名称来辨别用途很重要,因此命名要规范 这篇文章可参考:Android 命名规范 (提高代码可以读性) 刚接触android的时候,命名都是按照拼音来,所以有的时候想看懂命名 ...

  3. Android 你可能忽略的提高敲代码效率的方式

    Android 你可能忽略的提高敲代码效率的方式

  4. Android 自定义注解(Annotation)

    现在市面上很多框架都有使用到注解,比如butterknife库.EventBus库.Retrofit库等等.也是一直好奇他们都是怎么做到的,注解的工作原理是啥.咱们能不能自己去实现一个简单的注解呢. ...

  5. 提高代码质量 CheckStyle FindBugs PMD

    提高代码质量-工具篇 注:这是一篇翻译文章,原文:How to improve quality and syntax of your Android code,为了理解连贯,翻译过程中我修改了一些陈述 ...

  6. Android Studio 单刷《第一行代码》系列 01 —— 第一战 HelloWorld

    前言(Prologue) 本系列将使用 Android Studio 将<第一行代码>(书中讲解案例使用Eclipse)刷一遍,旨在为想入坑 Android 开发,并选择 Android ...

  7. Android Studio 单刷《第一行代码》系列 02 —— 日志工具 LogCat

    前情提要(Previously) 本系列将使用 Android Studio 将<第一行代码>(书中讲解案例使用Eclipse)刷一遍,旨在为想入坑 Android 开发,并选择 Andr ...

  8. Android提供了5种方式存储数据:

    --使用SharedPreferences存储数据: --文件存储数据: --SQLite数据库存储数据: --使用ContentProvider存储数据: --网络存储数据: 一:使用SharedP ...

  9. 如何在Android开发中让你的代码更有效率

    最近看了Google IO 2012年的一个视频,名字叫做Doing More With Less: Being a Good Android Citizen,主要是讲如何用少少的几句代码来改善And ...

随机推荐

  1. Angular RxJs:针对异步数据流编程工具

    一. RxJs:针对异步数据流编程工具 1. 创建subject类对象(发送方) 2. subject.subscribe(观察者); (注册观察者对象observer,可以注册多个相当于回调函数取数 ...

  2. centos7.5优化系统脚本(虚拟机下)

    #!/usr/bin/bash #安装常用软件,首先必须自行调整好网卡配置文件,保证可以上网,否则,下列优化会失败 yum -y install wget vim lrzsz bash-complet ...

  3. 国产安全自主可控IT智能运维管理解决方案

    新一轮科技革命和产业变革席卷全球,大数据.云计算.物联网.人工智能.区块链等新技术不断涌现,数字经济正深刻地改变着人类的生产和生活方式,作为经济增长新动能的作用日益凸显.伴随增长的,还有网络中不断涌现 ...

  4. c语言标准I/O

    头文件 <stdio.h> 打开/关闭文件 FILE *fopen(char *filename, char *mode); 如果正常打开返回FILE指针,否则返回NULL mode常用值 ...

  5. ExecutionContext(执行上下文)综述

    >>返回<C# 并发编程> 1. 简介 2. 同步异步对比 3. 上下文的捕获和恢复 4. Flowing ExecutionContext vs Using Synchron ...

  6. vue循环语句

    循环使用 v-for 指令. v-for 指令需要以 site in sites 形式的特殊语法, sites 是源数据数组并且 site 是数组元素迭代的别名. v-for 可以绑定数据到数组来渲染 ...

  7. java工作流系统jflow表单引擎字段扩展组件介绍

    关键词:工作流快速开发平台  工作流流设计  业务流程管理   asp.net 开源工作流  bpm工作流系统  java工作流主流框架  自定义工作流引擎 表单设计器  流程设计器 装饰类图片 用于 ...

  8. 13.Android-ListView使用、BaseAdapter/ArrayAdapter/SimpleAdapter适配器使用

    1.ListView ListView 是 Android 系统为我们提供的一种列表显示的一种控件,使用它可以用来显示我们常见的列表形式.继承自抽象类 AdapterView.继承图如下所示: 以微信 ...

  9. Android中通过数组资源文件xml与适配器两种方式给ListView列表视图设置数据源

    场景 实现效果如下 注: 博客: https://blog.csdn.net/badao_liumang_qizhi 关注公众号 霸道的程序猿 获取编程相关电子书.教程推送与免费下载. 实现 将布局改 ...

  10. 在C#下使用TensorFlow.NET训练自己的数据集

    在C#下使用TensorFlow.NET训练自己的数据集 今天,我结合代码来详细介绍如何使用 SciSharp STACK 的 TensorFlow.NET 来训练CNN模型,该模型主要实现 图像的分 ...