1、元注解
 
概念:用来定义其他注解的注解,自定义注解的时候,需要使用它来定义我们的注解。
 
在jdk 1.5之后提供了 java.lang.annotation 来支持注解功能
 
常见的四种元注解有 :
@Target (目标,  注解可以使用的地方,参数是一个ElementType 枚举)
@Retention  (保持性, 描述注解的生命周期  ) 
@Inherited ( 可继承的, 参数true or false ,表示是否允许子类继承该注解,默认false)
@Document (文档化,表明注解可以被javadoc 此类工具文档化)
 
1.1 @Target
@Target ElementType 枚举类型
 
ElementType.Type
接口、类、注解、枚举
ElementType.FIELD
字段、枚举常量
ElementType.METHOD
方法
ElementType.PARAMETER
方法参数
ElementType.CONSTRUCOTOR
构造函数
ElementType.LOCAL_VARIABLE
局部变量
ElementType.ANNOTATION_TYPE
注解
Element.PACKAGE
1.2 @Retention
 
 用于描述注解的生命周期, 注解在什么地方使用有效
参数 RetentionPolicy 枚举对象
 
RetentionPolicy.SOURCE
源文件,当java文件被编译成class文件时,注解失效
RetentionPolicy.CLASS
注解存在class 文件,当jvm 加载class文件时,注解生效,默认指定的参数
RetentionPolicy.RUNTIME
注解保存到class文件,jvm加载class文件后,依然有效
周期有效性, RUNTIME > CLASS > SOURCE
 
1.3 @Document
  标记自定义注解可被javadoc 此类文档化
 
1.4 @Inherited
 @Inherited    表明我们标记的注解是被继承的,如果一个父类使用@Inherited 修饰的注解,则允许子类继承该父类的注解
 
二、自定义注解
 
步骤:
1、申明注解,确定注解的运行生命周期、目标、参数
2、注解解析:找到被注解类的方法、属性。添加自定义注解的一些操作
 
案例1、注解创建对象
2.1申明注解AutoCreateObject
  1. import java.lang.annotation.ElementType;
  2. import java.lang.annotation.Retention;
  3. import java.lang.annotation.RetentionPolicy;
  4. import java.lang.annotation.Target;
  5.  
  6. /**
  7. * author: rexkell
  8. * explain:
  9. */
  10. @Target(ElementType.FIELD)
  11. @Retention(RetentionPolicy.RUNTIME)
  12. public @interface AutoCreateObject {
  13. }

2.2解析注解

  1. import java.lang.reflect.Constructor;
  2. import java.lang.reflect.Field;
  3. import java.lang.reflect.InvocationTargetException;
  4.  
  5. /**
  6. * author: rexkell
  7. * explain:
  8. */
  9. public class AutoCreateProcess {
  10. public static void bind(final Object object){
  11. Class parentClass=object.getClass();
  12. Field[] fields= parentClass.getFields();
  13. for (Field field: fields){
  14. AutoCreateObject autoCreateObject= field.getAnnotation(AutoCreateObject.class);
  15. if (autoCreateObject!=null){
  16. field.setAccessible(true);
  17. try {
  18. Class<?> autoCreateClass= field.getType();
  19. Constructor autoCreateConstructor= autoCreateClass.getConstructor();
  20. field.set(object,autoCreateConstructor.newInstance());
  21. } catch (NoSuchMethodException e) {
  22. e.printStackTrace();
  23. }catch (IllegalAccessException e){
  24. e.printStackTrace();
  25. }catch (InvocationTargetException e){
  26. e.printStackTrace();
  27. }catch (InstantiationException e){
  28. e.printStackTrace();
  29. }
  30.  
  31. }
  32. }
  33. }
  34. }
  1. @AutoCreateObject
    Students students;
  1. //创建对象
    AutoCreateProcess.bind(this);

3、模拟bindViewId

3.1、创建一个java Module

  1. implementation 'com.squareup:javapoet:1.9.0'
  2. implementation 'com.google.auto.service:auto-service:1.0-rc2'

3.2 申明注解

  1. import java.lang.annotation.RetentionPolicy;
  2. import java.lang.annotation.Target;
  3.  
  4. /**
  5. * author: rexkell
  6. * explain:
  7. */
  8. @Target(ElementType.FIELD)
  9. @Retention(RetentionPolicy.CLASS)
  10. public @interface BindView {
  11. int value() default -1;
  12. }

3.3 解析注解

  1. import android.app.Activity;
  2.  
  3. import java.lang.reflect.InvocationTargetException;
  4. import java.lang.reflect.Method;
  5. import java.util.HashMap;
  6. import java.util.Map;
  7.  
  8. /**
  9. * author: rexkell
  10. * explain:
  11. */
  12. public class MyBindView {
  13. private static Map<Class, Method> classMethodMap=new HashMap<>();
  14. public static void bind(Activity target){
  15. if (target!=null){
  16. Method method = classMethodMap.get(target.getClass());
  17. try {
  18. if (method==null){
  19. //获取编译生成的注解类
  20. String bindClassName= target.getPackageName()+".Bind"+target.getClass().getSimpleName();
  21. Class bindClass=Class.forName(bindClassName);
  22. method=bindClass.getMethod("bindView",target.getClass());
  23. classMethodMap.put(target.getClass(),method);
  24. }
  25. method.invoke(null,target);
  26. } catch (Exception e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. }
  31. }

由于是编译时产生的注解,需要通过 extends AbstractProcessor 来实现

  1. import com.google.auto.service.AutoService;
  2. import com.squareup.javapoet.ClassName;
  3. import com.squareup.javapoet.JavaFile;
  4. import com.squareup.javapoet.MethodSpec;
  5. import com.squareup.javapoet.TypeName;
  6. import com.squareup.javapoet.TypeSpec;
  7.  
  8. import java.io.IOException;
  9. import java.util.HashMap;
  10. import java.util.HashSet;
  11. import java.util.Locale;
  12. import java.util.Map;
  13. import java.util.Set;
  14.  
  15. import javax.annotation.processing.AbstractProcessor;
  16. import javax.annotation.processing.ProcessingEnvironment;
  17. import javax.annotation.processing.Processor;
  18. import javax.annotation.processing.RoundEnvironment;
  19. import javax.annotation.processing.SupportedSourceVersion;
  20. import javax.lang.model.SourceVersion;
  21. import javax.lang.model.element.Element;
  22. import javax.lang.model.element.Modifier;
  23. import javax.lang.model.element.TypeElement;
  24. import javax.lang.model.util.Elements;
  25.  
  26. /**
  27. * author: rexkell
  28. * explain:
  29. */
  30. @AutoService(Processor.class)
  31. @SupportedSourceVersion(SourceVersion.RELEASE_7)
  32. public class BindProcess extends AbstractProcessor {
  33. private Elements mElementsUtil;
  34. private Map<TypeElement,Set<Element>> mBindViewElems;
  35.  
  36. @Override
  37. public synchronized void init(ProcessingEnvironment processingEnv) {
  38. super.init(processingEnv);
  39. mElementsUtil=processingEnv.getElementUtils();
  40. mBindViewElems=new HashMap<>();
  41.  
  42. }
  43.  
  44. @Override
  45. public Set<String> getSupportedAnnotationTypes() {
  46. //添加需要解析的自定义注解类
  47. Set<String> types=new HashSet<>();
  48. types.add(BindView.class.getCanonicalName());
  49. types.add(BindLayout.class.getCanonicalName());
  50. return types;
  51. }
  52.  
  53. @Override
  54. public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
  55. System.out.println("Process start!");
  56. initBindElems(roundEnv.getElementsAnnotatedWith(BindView.class));
  57. generateJavaClass();
  58. System.out.println("Process finish!");
  59. return true;
  60. }
  61. //初始化绑定的控件
  62. private void initBindElems(Set<? extends Element> bindElems){
  63. for (Element bindElem : bindElems){
  64. TypeElement enclosedElem=(TypeElement) bindElem.getEnclosingElement();
  65. Set<Element> elems=mBindViewElems.get(enclosedElem);
  66. if (elems==null){
  67. elems=new HashSet<>();
  68. mBindViewElems.put(enclosedElem,elems);
  69. System.out.println(enclosedElem.getSimpleName());
  70. }
  71. elems.add(bindElem);
  72. System.out.println("Add bind elem "+bindElem.getSimpleName());
  73. }
  74. }
  75. private void generateJavaClass(){
  76. //生成Bind+ClassName+.class 文件,文件内容实现findViewById
  77. for (TypeElement enclosedElem: mBindViewElems.keySet()){
  78. MethodSpec.Builder methodSpesBuilder = MethodSpec.methodBuilder("bindView")
  79. .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
  80. .addParameter(ClassName.get(enclosedElem.asType()),"activity")
  81. .returns(TypeName.VOID);
  82. BindLayout bindLayoutAnno =enclosedElem.getAnnotation(BindLayout.class);
  83. if (bindLayoutAnno!=null){
  84. methodSpesBuilder.addStatement(String.format(Locale.US,"activity.setContentView(%d)",bindLayoutAnno.value()));
  85. }
  86. for (Element bindElem : mBindViewElems.get(enclosedElem)){
  87. methodSpesBuilder.addStatement(String.format(Locale.US,"activity.%s=(%s)activity.findViewById(%d)",
  88. bindElem.getSimpleName(),bindElem.asType(),bindElem.getAnnotation(BindView.class).value()));
  89. }
  90. TypeSpec typeSpec=TypeSpec.classBuilder("Bind"+enclosedElem.getSimpleName())
  91. .superclass(TypeName.get(enclosedElem.asType()))
  92. .addModifiers(Modifier.FINAL,Modifier.PUBLIC)
  93. .addMethod(methodSpesBuilder.build())
  94. .build();
  95. JavaFile file = JavaFile.builder(getPackageName(enclosedElem),typeSpec).build();
  96. try {
  97. file.writeTo(processingEnv.getFiler());
  98. } catch (IOException e) {
  99. e.printStackTrace();
  100. }
  101.  
  102. }
  103. }
  104. private String getPackageName(TypeElement typeElement){
  105. return mElementsUtil.getPackageOf(typeElement).getQualifiedName().toString();
  106. }
  107.  
  108. }

3.4 在需要使用bindViewId 注解中引入模块。

  1. @BindView(R.id.edt_longitude)
  2. EditText edtLongitude;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. SharedPreferences sharedPreferences= this.getSharedPreferences("theme",MODE_PRIVATE);
  7. int themeId=sharedPreferences.getInt("themeId",2);
  8. if (themeId==1){
  9. setTheme(R.style.BaseAppThemeNight);
  10. }else if (themeId==0){
  11. setTheme(R.style.AppTheme);
  12. }
  13. setContentView(R.layout.activity_main);
  14. MyBindView.bind(this);
  15. }
 

Android自定义注解的更多相关文章

  1. Android 自定义注解(Annotation)

    现在市面上很多框架都有使用到注解,比如butterknife库.EventBus库.Retrofit库等等.也是一直好奇他们都是怎么做到的,注解的工作原理是啥.咱们能不能自己去实现一个简单的注解呢. ...

  2. Android自定义工具类获取按钮并绑定事件(利用暴力反射和注解)

    Android中为按钮绑定事件的有几种常见方式,你可以在布局文件中为按钮设置id,然后在MainActivity中通过findViewById方法获取按钮对象实例,再通过setOnClickListe ...

  3. Android面试基础(一)IOC(DI)框架(ViewUtils)讲解_反射和自定义注解类

    1. Android中的IOC(DI)框架 1.1 ViewUtils简介(xUtils中的四大部分之一) IOC: Inverse of Controller 控制反转. DI: Dependenc ...

  4. 【转】ANDROID自定义视图——onLayout源码 流程 思路详解

    转载(http://blog.csdn.net/a396901990) 简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量——onMeasure():决定View的大小 2.布局 ...

  5. java自定义注解类

    一.前言 今天阅读帆哥代码的时候,看到了之前没有见过的新东西, 比如java自定义注解类,如何获取注解,如何反射内部类,this$0是什么意思? 于是乎,学习并整理了一下. 二.代码示例 import ...

  6. android 自定义动画

    android自定义动画注意是继承Animation,重写里面的initialize和applyTransformation,在initialize方法做一些初始化的工作,在applyTransfor ...

  7. Jackson 通过自定义注解来控制json key的格式

    Jackson 通过自定义注解来控制json key的格式 最近我这边有一个需求就是需要把Bean中的某一些特殊字段的值进行替换.而这个替换过程是需要依赖一个第三方的dubbo服务的.为了使得这个转换 ...

  8. 自定义注解之运行时注解(RetentionPolicy.RUNTIME)

    对注解概念不了解的可以先看这个:Java注解基础概念总结 前面有提到注解按生命周期来划分可分为3类: 1.RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成clas ...

  9. JAVA自定义注解

    在学习使用Spring和MyBatis框架的时候,使用了很多的注解来标注Bean或者数据访问层参数,那么JAVA的注解到底是个东西,作用是什么,又怎样自定义注解呢?这篇文章,即将作出简单易懂的解释. ...

随机推荐

  1. layui省市区三级联动城市选择

    基于layui框架制作精美的省市区下拉框三级联动菜单选择, 支持三级联动城市选择,点击提交获取选中值代码. 示例图如下: 资源链接: https://pan.baidu.com/s/1s6l8iDBE ...

  2. Centos7下的zabbix安装与部署

    目录: 1.Zabbix介绍 2.LAMP/LNMP介绍 3.Zabbix安装与部署 1.Zabbix介绍 zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案. ...

  3. IDEA 第三方jar包 使用

    1,加入lib包中,在pom中添加 <dependency> <groupId>com.sss</groupId> <artifactId>包名< ...

  4. R基础绘图

    本节内容 0:小知识 1:绘图系统散点图的特征 2:基础绘图函数 3:基础绘图参数 4:图形设备 5:案例操作5个图形 0:小知识 summary() ## 对数据框或者向量进行描述性数据 read. ...

  5. Less(3)

    1.先判断注入类型 (1)首先看到要求,要求传一个ID参数,并且要求是数字型的:?id=1 (2)再输入?id=1' 显示报错,报错信息多了一个括号,判断接收到的参数可能为id=('1') (3)输入 ...

  6. nginx学习(三):nginx的进程模型

    概述 nginx 进程分为 master进程和work进程 1.打开配置文件查看,这里我修改为2 [root@xxx conf]# vim nginx.conf #user nobody; worke ...

  7. SP2713 GSS4 - Can you answer these queries IV 分块

    问题描述 LG-SP2713 题解 分块,区间开根. 如果一块的最大值是 \(1\) ,那么这个块就不用开根了. 如果最大值不是 \(1\) ,直接暴力开就好了. \(\mathrm{Code}\) ...

  8. WPF Datagrid 控制 第一行和第一列之间的空白

    原文:WPF Datagrid 控制 第一行和第一列之间的空白 这个位置就是 这里 我们更改 DataGridControltemplate 模板 看树形结构 里面是一个BUtton 功能是全选 能找 ...

  9. Luogu P5298 [PKUWC2018]Minimax

    好劲的题目啊,根本没往线段树合并方面去想啊 首先每种权值都有可能出现,因此我们先排个序然后一个一个求概率 由于此时数的值域变成\([1,m]\)(离散以后),我们可以设一个DP:\(f_{x,i}\) ...

  10. golang--海量用户即使通讯系统

    功能需求: 用户注册 用户登录 显示在线用户列表 群聊 点对点聊天 离线留言