Android注解学习笔记
来源:互联网 发布:数据库设计与开发 下载 编辑:程序博客网 时间:2024/06/05 06:33
本文学习自《Android注解快速入门和实用解析》。
元注解
java提供的基础注解,用来注解其他自定义注解,解释说明作用,位于sdk/sources/android-25/java/lang/annotation
目录下
元注解有:
@Retention:注解保留的生命周期
@Target:注解对象的作用范围
@Inherited:标明的注解,在其作用的类上,能否被继承
@Documented:javadoc的工具文档化
@Retention
说明了注解的生命周期,对应RetentionPolicy枚举,标明注解何时生效。
SOURCE:只在源码中有效,编译时被抛弃,如
@override
CLASS:编译时生效
RUNTIME:运行时生效
@Target
标明了注解的作用范围,对应于ElementType枚举
TYPE
FIELD
METHOD
PARAMETER
CONSTRUCTOR
LOCAL_VARIABLE
ANNOTATION_TYPE
PACKAGE
TYPE_PARAMETER
TYPE_USE
/** * Nullable表明 * bind方法的参数target和返回值Data可以为null */ @Nullable public static Data bind(@Nullable Context target) { //do someThing and return return bindXXX(target); }
@Inherited
子类默认无法继承父类的注解,Inherited
注解可以使子类继承注释,但是只能作用在类上,无法作用在方法和变量上。
@Retention(RetentionPolicy.RUNTIME) @Inherited public @interface AInherited { String value(); } @Retention(RetentionPolicy.RUNTIME) public @interface BNotInherited { String value(); } @AInherited("Inherited") @BNotInherited("没Inherited") public class Parent { @AInherited("Inherited") @BNotInherited("没Inherited") public void testOverride(){ } @AInherited("Inherited") @BNotInherited("没Inherited") public void testNotOverride(){ }} /** * Child继承了Parent的AInherited注解 * BNotInherited因为没有@Inherited声明,不能被继承 */public class Child extends Parent { /** * 重写的testOverride不继承任何注解 * 因为Inherited不作用在方法上 */ @Override public void testOverride() { } /** * testNotOverride没有被重写 * 所以注解AInherited和BNotInherited依然生效。 */}
自定义注解
运行时注解
首先,创建一个注解遵循: public @interface 注解名 {方法参数},如下方@getViewTo
注解:
@Target({ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)public @interface getViewTo { int value() default -1;}
然后如下方所示,我们将注解描述在Activity的成员变量mTv
和mBtn
中,在App运行时,通过反射将findViewbyId
得到的控件,注入到mTv
和mBtn
中。
@getViewTo(R.id.textview) private TextView mTv; @getViewTo(R.id.button) private Button mBtn;
private void getAllAnnotationView() { //获得成员变量 Field[] fields = this.getClass().getDeclaredFields(); for (Field field : fields) { try { //判断注解 if (field.getAnnotations() != null) { //确定注解类型 if (field.isAnnotationPresent(GetViewTo.class)) { //允许修改反射属性 field.setAccessible(true); GetViewTo getViewTo = field.getAnnotation(GetViewTo.class); //findViewById将注解的id,找到View注入成员变量中 field.set(this, findViewById(getViewTo.value())); } } } catch (Exception e) { } } }
编译时注解
注解处理器AbstractProcessor
是一个javac的工具,用来在编译时扫描和处理,一般第三方注解相关的类库,都有一个Compiler命名的Module,这里面一般都是注解处理器。
@AutoService(Processor.class)public class CustomProcessor extends AbstractProcessor { /** * 注解处理器的初始化 * 一般在这里获取我们需要的工具类 * @param processingEnvironment 提供工具类Elements, Types和Filer */ @Override public synchronized void init(ProcessingEnvironment env){ super.init(env); //Element代表程序的元素,例如包、类、方法。 mElementUtils = env.getElementUtils(); //处理TypeMirror的工具类,用于取类信息 mTypeUtils = env.getTypeUtils(); //Filer可以创建文件 mFiler = env.getFiler(); //错误处理工具 mMessages = env.getMessager(); } /** * 处理器实际处理逻辑入口 * @param set * @param roundEnvironment 所有注解的集合 * @return */ @Override public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { //do someThing } //指定注解处理器是注册给哪个注解的,返回指定支持的注解类集合。 @Override public Set<String> getSupportedAnnotationTypes() { Set<String> sets = new LinkedHashSet<String>(); //大部分class而已getName、getCanonicalNam这两个方法没有什么不同的。 //但是对于array或内部类等就不一样了。 //getName返回的是[[Ljava.lang.String之类的表现形式, //getCanonicalName返回的就是跟我们声明类似的形式。 sets(BindView.class.getCanonicalName()); return sets; } //指定Java版本,一般返回最新版本即可 @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); }}
一般处理器处理逻辑:
遍历得到源码中,需要解析的元素列表。
判断元素是否可见和符合要求。
组织数据结构得到输出类参数。
输入生成java文件。
错误处理。
Processor处理过程中会扫描源码,代码中的每一部分都是个特定类型的Element,就像XML文件里面的层级一样,类、变量、方法等都属于不同的Element层级。每个Element代表一个静态的、语言类级别的构件。
package android.demo; // PackageElement// TypeElementpublic class DemoClass { // VariableElement private boolean mVariableType; // VariableElement private VariableClassE m VariableClassE; // ExecuteableElement public DemoClass () { } // ExecuteableElement public void resolveData (Demo data //TypeElement ) { }}
Element
代表源码,TypeElement
代表源码中的类型元素,TypeElement
只能获取到相对应的元素,不能获得类的信息,可以通过element.asType()
获取到TypeMirror
,TypeMirror
可以获取类信息。
知道了Element
,我们就可以通过process
中的RoundEnvironment
去获取,扫描到的所有元素,通过env.getElementsAnnotatedWith
,我们可以获取被@BindView
注解的元素的列表,其中validateElement
校验元素是否可用。
env.getElementsAnnotatedWith
返回的是所有被@BindView
注解的一个列表,有时候我们需要加个判断,比如这个元素是否是个类。
@Override public boolean process(Set<? extends TypeElement> an, RoundEnvironment env) { for (Element e : env.getElementsAnnotatedWith(BindView.class)) { // 检查元素是否是一个类 if (ae.getKind() != ElementKind.CLASS) { ... } }
错误处理,在处理器中,我们不能直接抛出一个异常,因为在process()中抛出一个异常,会导致运行注解处理器的JVM崩溃,导致跟踪栈信息十分混乱。因此,注解处理器就有一个Messager类,一般通过messager.printMessage( Diagnostic.Kind.ERROR, StringMessage, element)
即可正常输出错误信息。
编译时注解是在编译时生成java文件,将生成的java文件注入到源码中,不像运行时注解那样通过反射机制浪费效率。
- Android注解学习笔记
- Android Annotation注解学习笔记
- Android注解框架AndroidAnnotations学习笔记
- Android注解框架AndroidAnnotations学习笔记2
- 学习笔记--JavaBean,注解
- Struts2学习笔记--注解
- 注解学习笔记代码
- spring注解学习笔记
- Java 注解学习笔记
- Java 注解学习笔记
- java注解学习笔记
- Spring 注解学习笔记
- Spring注解学习笔记
- Spring注解@学习笔记
- spring注解学习笔记
- java8 注解学习笔记
- java注解学习笔记
- Spring 注解学习笔记
- 拥抱大前端 盘点那些值得你了解的最佳开发实践
- 【第1110期】SVG 路径动画简易指南
- osgEarth无数据像素透明案例 25.nodata.earth
- 【SpringMVC】springmvc与struts2的区别(九)
- 详解 CSS 居中布局技巧
- Android注解学习笔记
- jQuery 变量数字相加
- 模块API之__symbol_get/__symbol_put
- 使用VS2013 + EF6 + .NET4.5 连接Mysql数据库
- ROS_kinetic下rgbdslam_V2的安装和使用
- 设计模式-----创建型之工厂模式
- 李飞飞CS231n2017课程双语字幕版上线 !(附课程链接)
- 独家 | PHM数据竞赛首个中国夺冠团队经验分享(常用模型&赛题详解&PPT&视频)
- 网关相关