归志宁无五亩园,读书本意在元元。这篇文章主要讲述Android新增的注解相关的知识,希望能为你提供帮助。
环境使用android注解前需要导入相关的包
compile ‘com.android.support:support-annotations:latest.integration‘
注意:如果我们已经引入了appcompat则没有必要再次引用support-annotations,因为appcompat默认包含了对其引用
使用Android注解给我们提供了三种主要和其他注释供我们使用:
- IntDef和StringDef注解;
- 资源类型注解;
- Null注解;
- 其他实用注解
方案一
1 public class UserI { 2public staticint childe=0x1; 3public staticint man=0x2; 4public staticint girl=0x3; 5 6 7private int userType; 8 9public int getUserType() { 10return userType; 11} 12 13public void setUserType(int userType) { 14this.userType = userType; 15} 16 }
估计大家常用的就是这样的方式去解决这样的需求,但是上述实现存在一个问题:
setUserType
设置的是一个int
类型的变量,既然如此我们可以如此调用:1 UserI userI=new UserI(); 2/*正确调用*/ 3userI.setUserType(userI.childe); 4 5/*错误调用*/ 6userI.setUserType(100);
错误方式下的调用也不会抛出异常,所以这样的实现方式存在逻辑泄漏的危险!
方案二
既然如此:想必这个时候大家想到的解决办法就是枚举了,下面研究下枚举的实现
1 public class UserE { 2 3private UserEmun userType; 4 5public UserEmun getUserType() { 6return userType; 7} 8 9public void setUserType(UserEmun userType) { 10this.userType = userType; 11} 12 13public static enum UserEmun { 14childe, 15man, 16girl 17} 18 } 19 20 21 调用: 22 23UserE userE=new UserE(); 24userE.setUserType(UserE.UserEmun.childe);
从实现方式和逻辑上看,方案二枚举确实能解决方案一存在的漏洞,但是这里有一点需要注意:
Enum
因为其相比方案一的常量来说,占用内存相对大很多而受到曾经被Google
列为不建议使用。既然枚举也有它相关的缺陷,那如何完美解决这样的需求呢,以下完美实现-就是
Android
中用注解来替换java
的枚举;完美方案
Android中
新引入的替代枚举的注解有IntDef
和StringDef
,他们唯一的区别一个是int
类型,一个是string
类型,下面我们就以IntDef
为例讲解如何使用构建定义注解
1 public class UserInter { 2public static final int childe = 0x1; 3public static final int man = 0x2; 4public static final int girl = 0x3; 5public static final int other = 0x4; 6 7@IntDef({childe, man, girl}) 8@Retention(RetentionPolicy.SOURCE) 9public @interface UserInters{} 10 11 }
@Retention
表示注解类型的存活时长和@interface
定义一个注解,具体详细用法可查看上章Java注解
注意:这里定义的
other
并没有用IntDef
修饰使用:
设置变量,设置get和set方法
1 public class UserInter { 2public static final int childe = 0x1; 3public static final int man = 0x2; 4public static final int girl = 0x3; 5public static final int other = 0x4; 6 7@IntDef({childe, man, girl}) 8@Retention(RetentionPolicy.SOURCE) 9public @interface UserInters{} 10 11private int userType; 12 13@UserInters 14public int getUserType() { 15return userType; 16} 17 18public void setUserType(@UserInters int userType) { 19this.userType = userType; 20} 21 }
使用我们自定义的注解类
UserInters
,在get
方法上定义返回类型,和set
方法中设置传入参数的类型,这样在调用get
和set
方法时,编译器会自动帮我们检测是否合法!
1 UserInter userInter=new UserInter(); 2userInter.setUserType(UserInter.childe); 3 4userInter.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 如例讲解:
1 public class MainActivity extends AppCompatActivity { 2 3@Override 4protected void onCreate(Bundle savedInstanceState) { 5super.onCreate(savedInstanceState); 6setContentView(R.layout.activity_main); 7 8testDo(R.style.AppTheme); 9testDo(R.string.app_name); 10} 11 12 13private void testDo(@StringRes int str){ 14Log.e("tag","--------> "+getString(str)); 15} 16 17 }
我们定义
testDo
方法传入类型用@StringRes修饰,当方法被调用后编译器会自动匹配和检测,错误会及时的抛出错误异常,所以当调用testDo(R.style.AppTheme);
系统抛出异常如图文章图片
Null注解null注解对应的有两个详细的注解:
- @NonNull:不能为空
- @Nullable:可以为空
1 public class MainActivity extends AppCompatActivity { 2 3@Override 4protected void onCreate(Bundle savedInstanceState) { 5super.onCreate(savedInstanceState); 6setContentView(R.layout.activity_main); 7 8String msg=null; 9testDo(msg); 10} 11 12private void testDo(@NonNull String s){ 13Log.e("tag","--------> "+s); 14} 15 }
结果:
文章图片
编译器提示警告
@Nullable和@NonNull是相反的,使用一样,不啰嗦了!
注意:在使用的过程中发现在最新版本的AndroidStudio中不添加@Nullable和@NonNull,编译器也同样会提示响应的警告,所以这个注解可以忽略使用
文章图片
其他注解除了上述的主要功能注解外,还有一些实用的注解
Threading 注解thread注解是帮助我们指定方法在特定线程中执行处理,如果和指定的线程不一致,抛出异常;Threading 注解类型:
- @UiThread: UI线程
- @MainThread :主线程
- @WorkerThread: 子线程
- @BinderThread : 绑定线程
1 public class MainActivity extends AppCompatActivity { 2 3@Override 4protected void onCreate(Bundle savedInstanceState) { 5super.onCreate(savedInstanceState); 6setContentView(R.layout.activity_main); 7 8testDo(R.string.app_name); 9} 10 11@WorkerThread 12private void testDo(@StringRes int str){ 13Log.e("tag","--------> "+getString(str)); 14} 15 16 }
错误提示结果:
文章图片
我们指定testDo在子线程中处理,但是当前调用确实在主线程中,所以抛出异常
正确使用:
1 public class MainActivity extends AppCompatActivity { 2 3@Override 4protected void onCreate(Bundle savedInstanceState) { 5super.onCreate(savedInstanceState); 6setContentView(R.layout.activity_main); 7 8new Thread(new Runnable() { 9@Override 10public void run() { 11testDo(R.string.app_name); 12} 13}); 14} 15 16@WorkerThread 17private void testDo(@StringRes int str){ 18Log.e("tag","--------> "+getString(str)); 19} 20 21 }
结果:
文章图片
Value Constraints注解主要类型:
- @Size
- @IntRange
- @FloatRange
定义长度大小,可选择最小和最大长度使用
1 public class MainActivity extends AppCompatActivity { 2 3@Override 4protected void onCreate(Bundle savedInstanceState) { 5super.onCreate(savedInstanceState); 6setContentView(R.layout.activity_main); 7testDo(""); 8 9testDo("111"); 10 11testDo("1"); 12} 13 14private void testDo(@Size(min = 1,max = 2)String s){ 15Log.e("tag","--------> "+s); 16} 17 }
错误提示结果:
文章图片
这里size定了一个最小和最大长度,所以只有
testDo("1")
符合条件,其他调用都抛出了异常@IntRange使用
IntRange是用来指定int类型范围的注解
1 public class MainActivity extends AppCompatActivity { 2 3@Override 4protected void onCreate(Bundle savedInstanceState) { 5super.onCreate(savedInstanceState); 6setContentView(R.layout.activity_main); 7 8testDo(0); 9 10testDo(2); 11 12} 13 14private void testDo(@IntRange(from = 1,to = 100)int s){ 15Log.e("tag","--------> "+s); 16} 17 18 }
用IntRange定义了一个从1到100的s类型,所以在调用
testDo
方法时testDo(0)
不符合要求,会抛出异常错误提示结果:
文章图片
@FloatRange使用
FloatRange和IntRange用法一样,不过是指定的是float类型的数据对象,不重复阐述了
使用:
1 public class MainActivity extends AppCompatActivity { 2 3@Override 4protected void onCreate(Bundle savedInstanceState) { 5super.onCreate(savedInstanceState); 6setContentView(R.layout.activity_main); 7 8testDo(0); 9 10testDo(2); 11} 12 13 14private void testDo(@FloatRange(from = 1.0,to = 100.0)float s){ 15Log.e("tag","--------> "+s); 16} 17 18 }
错误提示结果:
文章图片
@CallSuper注解
@CallSuper
注解主要是用来强调在覆盖父类方法时,需要实现父类的方法,及时调用对应的super.***
方法,当用@CallSuper
修饰了该方法,如果子类覆盖的后没有实现对呀的super
方法会抛出异常正常使用:
1 public class CallSuperT { 2 3@CallSuper 4protectedvoid init(){ 5 6} 7 8class T extends CallSuperT{ 9 10@Override 11protected void init() { 12super.init(); 13} 14} 15 }
首先定义一个
CallSuperT
父类,然后生成一个T
继承CallSuperT
覆盖其init()
方法,父类中的init()
采用@CallSuper定义,如果我们去掉子类覆盖的super.init();
方法,AS在编译时会抛出错误信息修改:
1 public class CallSuperT { 2 3@CallSuper 4protectedvoid init(){ 5 6} 7 8class T extends CallSuperT{ 9 10@Override 11protected void init() { 12} 13} 14 }
错误提示结果:
文章图片
@CheckResult注解假设你定义了一个方法返回一个值,你期望调用者用这个值做些事情,那么你可以使用@CheckResult注解标注这个方法,强制用户定义一个相应的返回值,使用它!
使用:
首先修改上面的
CallSuperT
,定义一个retrunI
方法返回一个int
类型1 public class CallSuperT { 2 3@CheckResult 4public int retrunI(){ 5return 1; 6} 7 }
正确调用:
1 public class MainActivity extends AppCompatActivity { 2 3@Override 4protected void onCreate(Bundle savedInstanceState) { 5super.onCreate(savedInstanceState); 6setContentView(R.layout.activity_main); 7 8CallSuperT callSuperT = new CallSuperT(); 9int returns = callSuperT.retrunI(); 10} 11 }
如果这里去掉返回类型的定义对象:
int returns
则会抛出异常1 public class MainActivity extends AppCompatActivity { 2 3@Override 4protected void onCreate(Bundle savedInstanceState) { 5super.onCreate(savedInstanceState); 6setContentView(R.layout.activity_main); 7 8CallSuperT callSuperT = new CallSuperT(); 9callSuperT.retrunI(); 10} 11 }
错误提示结果:
文章图片
总结: 注解的作用:
- 提高我们的开发效率
- 更早的发现程序的问题或者错误
- 更好的增加代码的描述能力
- 更加利于我们的一些规范约束
- 提供解决问题的更优解
推荐阅读
- APP 资讯资源
- webAPP踩坑记录
- 使用Kotlin创建Android项目
- AtcoerE - Papple Sort
- Android-----购物车(包含侧滑删除,商品筛选,商品增加和减少,价格计算,店铺分类等)
- Android查缺补漏--Service和IntentService
- Android查缺补漏--Activity生命周期和启动模式
- Android查缺补漏--ContentProvider的使用
- AtCoder Regular Contest 088 E - Papple Sort(树状数组+结论)