Android新增的注解
环境
使用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中新引入的替代枚举的注解有IntDef和StringDef,他们唯一的区别一个是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方法中设置传入参数的类型,这样在调用get和set方法时,编译器会自动帮我们检测是否合法!
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新增的注解的更多相关文章
- Android中通过注解代替findViewById方法
转自:http://www.2cto.com/kf/201405/302998.html 这篇文章主要讲解注解实现findViewById的功能,首先我们来熟悉一下在java中怎么定义一个注解和解析一 ...
- 2.2、Android Studio通过注解提升代码检测
使用像Lint这样的代码检测工具可以帮助你发现问题和提升代码,但是代码检测在有些地方很难应用.例如,Android的资源ID,使用一个int类型来表示字符.图像.颜色或者其他资源类型所以代码检测工具不 ...
- 8 -- 深入使用Spring -- 2...5 Spring 3.0 新增的注解
8.2.5 Spring 3.0 新增的注解 @DependsOn @Lazy @DependsOn :用于强制初始化其他Bean.修饰Bean类或方法,可以指定一个字符串数组作为参数,每个数组元素对 ...
- 利用APT实现Android编译时注解
摘要: 一.APT概述 我们在前面的java注解详解一文中已经讲过,可以在运行时利用反射机制运行处理注解.其实,我们还可以在编译时处理注解,这就是不得不说官方为我们提供的注解处理工具APT (Anno ...
- 理解Android中的注解与反射
反射 Java反射(Reflection)定义 Java反射机制是指在运行状态中 对于任意一个类,都能知道这个类的所有属性和方法:对于任何一个对象,都能够调用它的任何一个方法和属性: 这样动态获取新的 ...
- Android运行时注解
Android的注解有编译时注解和运行时注解,本文就介绍下运行时注解. 其实非常简单,直接上代码:本文主要是替代传统的findViewById()的功能,就是在我们Activity中不需要再使用fin ...
- Android 编译时注解解析框架
2.注解 说道注解,竟然还有各种分类,得,这记不住,我们从注解的作用来反推其分类,帮助大家记忆,然后举例强化大家的记忆,话说注解的作用: 1.标记一些信息,这么说可能太抽象,那么我说,你见过@Over ...
- Android开发之注解式框架ButterKnife的使用
ButterKnife官网 其实ButterKnife的注解式,与xUtils的ViewUtils模块基本上差不多,只要用过xUtils,这个框架基本上就会了. 一.原理. 最近发现一个很好用的开源框 ...
- Android AOP之路三 Android上的注解
一.简单介绍 啥是注解.不懂的能够先看我上一篇文章. 在android 里面 注解主要用来干这么几件事: 和编译器一起给你一些提示警告信息. 配合一些ide 能够更加方便快捷 安全有效的编写java代 ...
随机推荐
- 修改win7远程桌面端口号
Windows 7/Vista/XP/2003等系统中的远程终端服务是一项功能非常强大的服务,同时也成了入侵者长驻主机的通道,入侵者可以利用一些手段得到管理员账号和密码并入侵主机.下面,我们来看看如何 ...
- Firefox显示 您的链接不安全 的解决办法
Firefox浏览器,今天突然打开网页的时候提醒,“您的链接不安全”,于是网页怎么刷新都打不开.后来几经查询终于解决,下面告诉大家该如何解决这种情况. 百度经验:jingyan.baidu.com 工 ...
- 汉字转拼音开源工具包Jpinyin介绍
最近要实现一个根据词语得到词语对应拼音的功能,找到了Jpinyin这个开源工具包,使用下来发现它非常强大,完全满足我的需求,下面对它做一个简单的介绍,希望能够帮助到有需要的朋友. https://gi ...
- 【Django】uWSGI和Gunicorn【转】
因为nginx等优秀的开源项目,有不少本来不是做服务器的同学也可以写很多服务器端的程序了.但是在聊天中会发现,大家虽然写了不少代码,但是对wsgi是什么,gunicorn是什么,反向代理又是什么并不了 ...
- python:数组/列表(remove()函数、append()函数、sort()函数、reverse()函数)
排序: 1:整理顺序 #冒泡 lista = [5,7,11,19,99,63,3,9,1] list = [] while lista != []: number = 0 for i in list ...
- druid 连接池的配置
dataSource配置 <!-- 基于Druid数据库链接池的数据源配置 --> <bean id="dataSource" class="com ...
- iOS学习之WebView的使用
1.使用UIWebView加载网页 运行XCode 4.3,新建一个Single View Application,命名为WebViewDemo. 2.加载WebView 在ViewControlle ...
- 简单例子让你很好的理解:协议与委托 (Protocol and Delegate)
1 协议: 协议,类似于Java或C#语言中的接口,它限制了实现类必须拥有哪些方法. 它是对对象行为的定义,也是对功能的规范. 示例: 1 2 3 4 5 6 7 8 9 // GoodChild.h ...
- 强大的vim配置文件,让编程更随意 (转载)
花了很长时间整理的,感觉用起来很方便,共享一下. 我的vim配置主要有以下优点: 1.按F5可以直接编译并执行C.C++.java代码以及执行shell脚本,按“F8”可进行C.C++代码的调试 2. ...
- linux tar 压缩
压缩文件 tar -czvf xxx.tar.gz yourdict 解压文件 tar xzf aa.tar.gz