环境

使用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. 编写一个参数JavaScript函数parseQueryString,它的用途是把url参数解析为一个对象

    var url = "http://www.taobao.com/index.php?key0=0&key1=1&key2=2............."; var ...

  2. 第六章 声明式服务调用: Spring Cloud Feign

    我们在使用 Spring Cloud Ribbon 时, 通常都会利用它对 RestTemplate 的请求拦截来实现对依赖服务的接口调用, 而 RestTemplate 已经实现了对 HTTP 请求 ...

  3. sublime text 怎么浏览包

    点击到设置里 里面有个包浏览.

  4. K2 Blackpearl中从数据库直接删除流程实例之K2ServerLog表

    转:http://www.cnblogs.com/dannyli/archive/2012/11/29/2794845.html /********************************** ...

  5. mongodb(三)

    索引详讲索引管理空间索引 for(var i = 0 ; i<200000 ;i++){ db.books.insert({number:i,name:i+"book"}) ...

  6. c++builder 画图 填充

    c++builder 画图 填充 void __fastcall TForm2::Button1Click(TObject *Sender) { Canvas->Brush->Color ...

  7. Dbvisualizer设置SQL语句自动提示

    Dbvisualizer默认不自动提示SQL语句的命令及查询的表,虽然可以通过Ctrl+/快捷键进行手动调用出提示信息,用习惯了PLSQL Developer难免有些不适应. 设置自动提示方法: 点击 ...

  8. margin+absolute布局:右栏固定主内容自适应 demo

    margin+absolute布局:右栏固定主内容自适应 demo 头部 Aside侧边栏区域 Main主内容区域 底部 #demo{width:80%;margin:auto;height:300p ...

  9. firebug,chrome调试工具的使用

    ​http://ued.taobao.org/blog/?p=5534 chrome调试 http://www.cnblogs.com/QLeelulu/archive/2011/08/28/2156 ...

  10. WCF配置多个终节点

    配置多个终节点的意义(自己理解):一个服务可以有多个终节点,网上也经常有人说终节点才是服务的真正的接口,的确如此,当我们为一个服务配置多个终节点时,就表明这个服务可以被以不同的方式访问(不同的绑定等等 ...