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
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* author: rexkell
* explain:
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoCreateObject {
}

2.2解析注解

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; /**
* author: rexkell
* explain:
*/
public class AutoCreateProcess {
public static void bind(final Object object){
Class parentClass=object.getClass();
Field[] fields= parentClass.getFields();
for (Field field: fields){
AutoCreateObject autoCreateObject= field.getAnnotation(AutoCreateObject.class);
if (autoCreateObject!=null){
field.setAccessible(true);
try {
Class<?> autoCreateClass= field.getType();
Constructor autoCreateConstructor= autoCreateClass.getConstructor();
field.set(object,autoCreateConstructor.newInstance());
} catch (NoSuchMethodException e) {
e.printStackTrace();
}catch (IllegalAccessException e){
e.printStackTrace();
}catch (InvocationTargetException e){
e.printStackTrace();
}catch (InstantiationException e){
e.printStackTrace();
} }
}
}
}
@AutoCreateObject
Students students;
//创建对象
AutoCreateProcess.bind(this);

3、模拟bindViewId

3.1、创建一个java Module

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

3.2 申明注解

import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* author: rexkell
* explain:
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.CLASS)
public @interface BindView {
int value() default -1;
}

3.3 解析注解

import android.app.Activity;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map; /**
* author: rexkell
* explain:
*/
public class MyBindView {
private static Map<Class, Method> classMethodMap=new HashMap<>();
public static void bind(Activity target){
if (target!=null){
Method method = classMethodMap.get(target.getClass());
try {
if (method==null){
//获取编译生成的注解类
String bindClassName= target.getPackageName()+".Bind"+target.getClass().getSimpleName();
Class bindClass=Class.forName(bindClassName);
method=bindClass.getMethod("bindView",target.getClass());
classMethodMap.put(target.getClass(),method);
}
method.invoke(null,target);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

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

import com.google.auto.service.AutoService;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec; import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set; import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements; /**
* author: rexkell
* explain:
*/
@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class BindProcess extends AbstractProcessor {
private Elements mElementsUtil;
private Map<TypeElement,Set<Element>> mBindViewElems; @Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
mElementsUtil=processingEnv.getElementUtils();
mBindViewElems=new HashMap<>(); } @Override
public Set<String> getSupportedAnnotationTypes() {
//添加需要解析的自定义注解类
Set<String> types=new HashSet<>();
types.add(BindView.class.getCanonicalName());
types.add(BindLayout.class.getCanonicalName());
return types;
} @Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
System.out.println("Process start!");
initBindElems(roundEnv.getElementsAnnotatedWith(BindView.class));
generateJavaClass();
System.out.println("Process finish!");
return true;
}
//初始化绑定的控件
private void initBindElems(Set<? extends Element> bindElems){
for (Element bindElem : bindElems){
TypeElement enclosedElem=(TypeElement) bindElem.getEnclosingElement();
Set<Element> elems=mBindViewElems.get(enclosedElem);
if (elems==null){
elems=new HashSet<>();
mBindViewElems.put(enclosedElem,elems);
System.out.println(enclosedElem.getSimpleName());
}
elems.add(bindElem);
System.out.println("Add bind elem "+bindElem.getSimpleName());
}
}
private void generateJavaClass(){
//生成Bind+ClassName+.class 文件,文件内容实现findViewById
for (TypeElement enclosedElem: mBindViewElems.keySet()){
MethodSpec.Builder methodSpesBuilder = MethodSpec.methodBuilder("bindView")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(ClassName.get(enclosedElem.asType()),"activity")
.returns(TypeName.VOID);
BindLayout bindLayoutAnno =enclosedElem.getAnnotation(BindLayout.class);
if (bindLayoutAnno!=null){
methodSpesBuilder.addStatement(String.format(Locale.US,"activity.setContentView(%d)",bindLayoutAnno.value()));
}
for (Element bindElem : mBindViewElems.get(enclosedElem)){
methodSpesBuilder.addStatement(String.format(Locale.US,"activity.%s=(%s)activity.findViewById(%d)",
bindElem.getSimpleName(),bindElem.asType(),bindElem.getAnnotation(BindView.class).value()));
}
TypeSpec typeSpec=TypeSpec.classBuilder("Bind"+enclosedElem.getSimpleName())
.superclass(TypeName.get(enclosedElem.asType()))
.addModifiers(Modifier.FINAL,Modifier.PUBLIC)
.addMethod(methodSpesBuilder.build())
.build();
JavaFile file = JavaFile.builder(getPackageName(enclosedElem),typeSpec).build();
try {
file.writeTo(processingEnv.getFiler());
} catch (IOException e) {
e.printStackTrace();
} }
}
private String getPackageName(TypeElement typeElement){
return mElementsUtil.getPackageOf(typeElement).getQualifiedName().toString();
} }

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

@BindView(R.id.edt_longitude)
EditText edtLongitude;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences sharedPreferences= this.getSharedPreferences("theme",MODE_PRIVATE);
int themeId=sharedPreferences.getInt("themeId",2);
if (themeId==1){
setTheme(R.style.BaseAppThemeNight);
}else if (themeId==0){
setTheme(R.style.AppTheme);
}
setContentView(R.layout.activity_main);
MyBindView.bind(this);
}
 

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. 利用Dynamics 365 Customer Engagement的标准导入功能导入附件。

    我是微软Dynamics 365 & Power Platform方面的工程师罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面 ...

  2. Android 亮度调节功能开发思路整理

    做 Android 音视频播放器开发的时候,我们基本都会遇到一类需求:音量 & 亮度 调节.其中做亮度调节功能的时候,发现还是有一定复杂度的. Android亮度调节分为两个类,分别是: An ...

  3. [转载] Java的四种引用关系

    目录 1 强引用 (Final Reference) 2 软引用 (Soft Reference) 2.1 案例1: 软引用的垃圾回收 2.2 案例2: 软引用缓存的使用 2.3 软引用的应用场景 3 ...

  4. dubbo解决本地开发直连

    问题: 在如今的分布式项目开发中,zookeeper + dubbo是最常见的,通常的使用是用zookeeper做注册中心,dubbo做rpc,然后服务部署就可以实现相互之间的远程通信.所以开发项目时 ...

  5. 初级模拟电路:3-8 BJT数据规格书(直流部分)

    回到目录 本小节我们以2N4123通用型BJT硅基晶体管为例,来介绍如何阅读BJT的数据规格书,点此链接可以阅读和下载2N4123的数据规格书. 1. 总体性能 打开datasheet后,首先看标题: ...

  6. 几款常见web扫描器的简要记录

    一.前期侦查 为了减少和目标系统的交互(防止触发报警),建议将目标站点镜像一份到本地 httrack(镜像网站到本地)  ====> 根据引导填入相关信息即可,使用非常简单 二.扫描 扫描分两种 ...

  7. 2015 经典的ImageCaptioning论文

    1.Show and Tell: A Neural Image Caption Generator Google团队的成果 整体处理流程: 1)通过CNN提取到图片的特征,简称feature. 2)而 ...

  8. Acwing40. 顺时针打印矩阵

    地址 https://www.acwing.com/solution/acwing/content/3623/ 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字. 样例 输入: [ [, ...

  9. python程序封装成exe流程

    在学习python的过程中,在IDE编写完成py项目,运行成功想要封装成exe,方便分享给不同的人即使别人没有安装python也可以使用. 封装的过程中遇到一些问题,记录一下,方便自己和他人查阅. 以 ...

  10. ClickHouse

    ClickHouse 是俄罗斯的Yandex于2016年开源的列式存储数据库(DBMS),主要用于在线分析处理查询(OLAP),能够使用SQL查询实时生成分析数据报告 1 安装前的准备1.1 Cent ...