环境

使用Android注解前需要导入相关的包

 compile 'com.android.support:support-annotations:latest.integration'

注意:如果我们已经引入了appcompat则没有必要再次引用support-annotations,因为appcompat默认包含了对其引用

使用

Android注解给我们提供了三种主要和其他注释供我们使用:

  • IntDef和StringDef注解;

  • 资源类型注解;

  • Null注解;

  • 其他实用注解


IntDef和StringDef注解替代枚举

这里我们采用假设一个问题然后一步步解决学习:假设有一个User对象,我们需要记录user类型的变量,如何实现呢?

方案一

 public class UserI {
public static int childe=0x1;
public static int man=0x2;
public static int girl=0x3; private int userType; public int getUserType() {
return userType;
} public void setUserType(int userType) {
this.userType = userType;
}
}

估计大家常用的就是这样的方式去解决这样的需求,但是上述实现存在一个问题:setUserType设置的是一个int类型的变量,既然如此我们可以如此调用:

 UserI userI=new UserI();
/*正确调用*/
userI.setUserType(userI.childe); /*错误调用*/
userI.setUserType(100);

错误方式下的调用也不会抛出异常,所以这样的实现方式存在逻辑泄漏的危险!


方案二

既然如此:想必这个时候大家想到的解决办法就是枚举了,下面研究下枚举的实现

 public class UserE {

     private UserEmun userType;

     public UserEmun getUserType() {
return userType;
} public void setUserType(UserEmun userType) {
this.userType = userType;
} public static enum UserEmun {
childe,
man,
girl
}
} 调用: UserE userE=new UserE();
userE.setUserType(UserE.UserEmun.childe);

从实现方式和逻辑上看,方案二枚举确实能解决方案一存在的漏洞,但是这里有一点需要注意:Enum因为其相比方案一的常量来说,占用内存相对大很多而受到曾经被Google列为不建议使用。

既然枚举也有它相关的缺陷,那如何完美解决这样的需求呢,以下完美实现-就是Android中用注解来替换java的枚举;


完美方案

Android中新引入的替代枚举的注解有IntDefStringDef,他们唯一的区别一个是int类型,一个是string类型,下面我们就以IntDef为例讲解如何使用

构建定义注解

 public class UserInter {
public static final int childe = 0x1;
public static final int man = 0x2;
public static final int girl = 0x3;
public static final int other = 0x4; @IntDef({childe, man, girl})
@Retention(RetentionPolicy.SOURCE)
public @interface UserInters{} }

@Retention表示注解类型的存活时长和@interface定义一个注解,具体详细用法可查看上章Java注解

注意:这里定义的other 并没有用IntDef修饰

使用:

设置变量,设置get和set方法

 public class UserInter {
public static final int childe = 0x1;
public static final int man = 0x2;
public static final int girl = 0x3;
public static final int other = 0x4; @IntDef({childe, man, girl})
@Retention(RetentionPolicy.SOURCE)
public @interface UserInters{} private int userType; @UserInters
public int getUserType() {
return userType;
} public void setUserType(@UserInters int userType) {
this.userType = userType;
}
}

使用我们自定义的注解类UserInters,在get方法上定义返回类型,和set方法中设置传入参数的类型,这样在调用getset方法时,编译器会自动帮我们检测是否合法!

  
 UserInter userInter=new UserInter();
userInter.setUserType(UserInter.childe); userInter.setUserType(UserInter.other);

在调用的地方我们先正确的设置一个IntDef定义的childe,再设置一个没有用IntDef修饰的other对象:

结果: 

从结果图片中可以发现,当设置一个没有被IntDef定义的对象时,编译器直接抛出了异常,到此我们就完美解决了第一种方案的泄露和第二中方案中的占用内存相对大的问题;


资源类型注解

常用的资源注解:

name exp
AnimRes 动画
AnimatorRes animator资源类型
AnyRes 任何资源类型
ArrayRes 数组资源类型
AttrRes 属性资源类型
BoolRes bool类型资源类型
ColorRes 颜色资源类型
DimenRes 长度资源类型
DrawableRes 图片资源类型
IdRes 资源id
InterpolatorRes 动画插值器
LayoutRes layout资源
MenuRes menu资源
RawRes raw资源
StringRes 字符串资源
StyleRes style资源
StyleableRes Styleable资源类型
TransitionRes transition资源类型
XmlRes xml资源

资源注解是为了防止我们在使用程序资源的时候,错误传递资源类型给函数,导致程序错误!

@StringRes 如例讲解:

 public class MainActivity extends AppCompatActivity {

     @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); testDo(R.style.AppTheme);
testDo(R.string.app_name);
} private void testDo(@StringRes int str){
Log.e("tag","-------->"+getString(str));
} }

我们定义testDo方法传入类型用@StringRes修饰,当方法被调用后编译器会自动匹配和检测,错误会及时的抛出错误异常,所以当调用testDo(R.style.AppTheme);系统抛出异常如图


Null注解

null注解对应的有两个详细的注解:

  • @NonNull:不能为空

  • @Nullable:可以为空

使用@NonNull注解修饰的参数不能为null。在下面的代码例子中,我们有一个取值为null的msg变量,它被作为参数传递给testDo函数,而该函数要求这个参数是非null的String类型

 public class MainActivity extends AppCompatActivity {

     @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); String msg=null;
testDo(msg);
} private void testDo(@NonNull String s){
Log.e("tag","-------->"+s);
}
}

结果:

编译器提示警告

@Nullable和@NonNull是相反的,使用一样,不啰嗦了!

注意:在使用的过程中发现在最新版本的AndroidStudio中不添加@Nullable和@NonNull,编译器也同样会提示响应的警告,所以这个注解可以忽略使用


其他注解

除了上述的主要功能注解外,还有一些实用的注解


Threading 注解

thread注解是帮助我们指定方法在特定线程中执行处理,如果和指定的线程不一致,抛出异常;Threading 注解类型:

  • @UiThread: UI线程

  • @MainThread :主线程

  • @WorkerThread: 子线程

  • @BinderThread : 绑定线程

下面以@WorkerThread为例:

 public class MainActivity extends AppCompatActivity {

     @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); testDo(R.string.app_name);
} @WorkerThread
private void testDo(@StringRes int str){
Log.e("tag","-------->"+getString(str));
} }

错误提示结果:

我们指定testDo在子线程中处理,但是当前调用确实在主线程中,所以抛出异常

正确使用:

 public class MainActivity extends AppCompatActivity {

     @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); new Thread(new Runnable() {
@Override
public void run() {
testDo(R.string.app_name);
}
});
} @WorkerThread
private void testDo(@StringRes int str){
Log.e("tag","-------->"+getString(str));
} }

结果:


Value Constraints注解

主要类型:

  • @Size

  • @IntRange

  • @FloatRange

@size使用

定义长度大小,可选择最小和最大长度使用

 public class MainActivity extends AppCompatActivity {

     @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testDo(""); testDo("111"); testDo("1");
} private void testDo(@Size(min = 1,max = 2)String s){
Log.e("tag","-------->"+s);
}
}

错误提示结果:

这里size定了一个最小和最大长度,所以只有testDo("1")符合条件,其他调用都抛出了异常

@IntRange使用

IntRange是用来指定int类型范围的注解


 public class MainActivity extends AppCompatActivity {

     @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); testDo(0); testDo(2); } private void testDo(@IntRange(from = 1,to = 100)int s){
Log.e("tag","-------->"+s);
} }

用IntRange定义了一个从1到100的s类型,所以在调用testDo方法时testDo(0)不符合要求,会抛出异常

错误提示结果:

@FloatRange使用

FloatRange和IntRange用法一样,不过是指定的是float类型的数据对象,不重复阐述了

使用:

 public class MainActivity extends AppCompatActivity {

     @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); testDo(0); testDo(2);
} private void testDo(@FloatRange(from = 1.0,to = 100.0)float s){
Log.e("tag","-------->"+s);
} }

错误提示结果:


@CallSuper注解

@CallSuper注解主要是用来强调在覆盖父类方法时,需要实现父类的方法,及时调用对应的super.***方法,当用@CallSuper修饰了该方法,如果子类覆盖的后没有实现对呀的super方法会抛出异常

正常使用:

 public class CallSuperT {

     @CallSuper
protected void init(){ } class T extends CallSuperT{ @Override
protected void init() {
super.init();
}
}
}

首先定义一个CallSuperT父类,然后生成一个T继承CallSuperT覆盖其init()方法,父类中的init()采用@CallSuper定义,如果我们去掉子类覆盖的super.init();方法,AS在编译时会抛出错误信息

修改:

 public class CallSuperT {

     @CallSuper
protected void init(){ } class T extends CallSuperT{ @Override
protected void init() {
}
}
}

错误提示结果:


@CheckResult注解

假设你定义了一个方法返回一个值,你期望调用者用这个值做些事情,那么你可以使用@CheckResult注解标注这个方法,强制用户定义一个相应的返回值,使用它!

使用: 
首先修改上面的CallSuperT ,定义一个retrunI方法返回一个int类型

 public class CallSuperT {

     @CheckResult
public int retrunI(){
return 1;
}
}

正确调用:

 public class MainActivity extends AppCompatActivity {

     @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); CallSuperT callSuperT = new CallSuperT();
int returns = callSuperT.retrunI();
}
}

如果这里去掉返回类型的定义对象:int returns则会抛出异常

 public class MainActivity extends AppCompatActivity {

     @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); CallSuperT callSuperT = new CallSuperT();
callSuperT.retrunI();
}
}

错误提示结果:


总结:

注解的作用:

  • 提高我们的开发效率

  • 更早的发现程序的问题或者错误

  • 更好的增加代码的描述能力

  • 更加利于我们的一些规范约束

  • 提供解决问题的更优解

使用Java注解和Android注解,能大幅度的提高我们的开发效率已经开发过程中的及时校验,避免一些因开发者疏忽而导致的问题,非常的实用!

Android新增的注解的更多相关文章

  1. Android中通过注解代替findViewById方法

    转自:http://www.2cto.com/kf/201405/302998.html 这篇文章主要讲解注解实现findViewById的功能,首先我们来熟悉一下在java中怎么定义一个注解和解析一 ...

  2. 2.2、Android Studio通过注解提升代码检测

    使用像Lint这样的代码检测工具可以帮助你发现问题和提升代码,但是代码检测在有些地方很难应用.例如,Android的资源ID,使用一个int类型来表示字符.图像.颜色或者其他资源类型所以代码检测工具不 ...

  3. 8 -- 深入使用Spring -- 2...5 Spring 3.0 新增的注解

    8.2.5 Spring 3.0 新增的注解 @DependsOn @Lazy @DependsOn :用于强制初始化其他Bean.修饰Bean类或方法,可以指定一个字符串数组作为参数,每个数组元素对 ...

  4. 利用APT实现Android编译时注解

    摘要: 一.APT概述 我们在前面的java注解详解一文中已经讲过,可以在运行时利用反射机制运行处理注解.其实,我们还可以在编译时处理注解,这就是不得不说官方为我们提供的注解处理工具APT (Anno ...

  5. 理解Android中的注解与反射

    反射 Java反射(Reflection)定义 Java反射机制是指在运行状态中 对于任意一个类,都能知道这个类的所有属性和方法:对于任何一个对象,都能够调用它的任何一个方法和属性: 这样动态获取新的 ...

  6. Android运行时注解

    Android的注解有编译时注解和运行时注解,本文就介绍下运行时注解. 其实非常简单,直接上代码:本文主要是替代传统的findViewById()的功能,就是在我们Activity中不需要再使用fin ...

  7. Android 编译时注解解析框架

    2.注解 说道注解,竟然还有各种分类,得,这记不住,我们从注解的作用来反推其分类,帮助大家记忆,然后举例强化大家的记忆,话说注解的作用: 1.标记一些信息,这么说可能太抽象,那么我说,你见过@Over ...

  8. Android开发之注解式框架ButterKnife的使用

    ButterKnife官网 其实ButterKnife的注解式,与xUtils的ViewUtils模块基本上差不多,只要用过xUtils,这个框架基本上就会了. 一.原理. 最近发现一个很好用的开源框 ...

  9. Android AOP之路三 Android上的注解

    一.简单介绍 啥是注解.不懂的能够先看我上一篇文章. 在android 里面 注解主要用来干这么几件事: 和编译器一起给你一些提示警告信息. 配合一些ide 能够更加方便快捷 安全有效的编写java代 ...

随机推荐

  1. Spring中application*的使用

    ApplicationAware 加载Spring配置文件时,如果Spring配置文件中所定义的Bean类实现了ApplicationContextAware 接口,那么在加载Spring配置文件时, ...

  2. Vue之cookie操作(原生)

    Vue之cookie操作(原生) 再vue组件中加入以下几个方法,然后调用即可. methods:{ //读取cookie,需要注意的是cookie是不能存中文的,如果需要存中文,解决方法是后端先进行 ...

  3. angularjs之向下一个页面传参

    原理: 1.在a标签跳转时,连接后增加一个参数值 2.在路由中接收 3.在控制器中接收 实现: 1.<a href="#/list/{{val.id}}"> 2.在js ...

  4. JS倒计时,自动提交表单!

    <form id="frm" action="http://www.baidu.com"> 考试还剩余<div id="time&q ...

  5. UNITY所谓的异步加载几乎全部是协程,不是线程;MAP3加载时解压非常慢

    实践证明,以下东西都是协程,并非线程(thread): 1,WWW 2,AssetBundle.LoadFromFileAsync 3,LoadSceneAsync 其它未经测试 此问题的提出是由于一 ...

  6. Hibernate的HQL中in参数设置

    平时经常用Hibernate,由于习惯表间不建立关联,所以HQL查询时候经常要用in语句. 我最常用的情况有2种: 1.in后是个子查询,如 FROM A WHERE A.ID IN (SELECT ...

  7. 打包jar文件并自动运行

    1,首先在eclipse 或MyEclipse 中测试通过,没有问题,(每次修改要update Maven) 2,修改pom.xml ---把build中改为<excludes> < ...

  8. Oracle中关于DateTime的一些描述

    转载自:http://www.cnblogs.com/fmxyw/archive/2008/08/26/1276850.html 在做话务报表,参考一下信息   to_date()与24小时制表示法及 ...

  9. css常用属性总结第二弹:id选择器

    承接上一篇class选择器,这一篇我们来说说css的id选择器. id选择器类似于类选择器,不过也有一些重要的差别,首先,id选择器前面有一个#号----称它为棋牌号吧,class为点号,用法就和cl ...

  10. js闭包的定义

    通过函数字面量创建的函数对象包含一个连接到外部上下文的连接,这叫做闭包. 还有一种定义:函数可以访问它被创建时所处的上下文环境,叫做闭包.