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. golang 处理 json 结构体

    首先 我们来看一下这个json 字串 { "resp": { ", "respMsg": "成功", "app" ...

  2. CreateWindowW()函数

    函数原型为: 该函数利用已经注册的窗口类 创建一个窗口,并返回该窗口的句柄 HWND CreateWindow( LPCTSTR lpClassName, //窗口类名称,也可以是控件名称 LPCTS ...

  3. 2018简约商务工作汇报工作总结公司培训团队介绍PPT模

    这几款ppt模板都是简约大气类型的,32页足够丰富,有完整结构框架,可以修改文字图片直接套用模板,是通用的商务ppt模板. 模版来源:http://ppt.dede58.com/gongzuohuib ...

  4. Microsoft Visual Studio 2017 找不到 Visual Studio Installer

    Microsoft Visual Studio 2017 找不到 Visual Studio Installer ? 打开vs2017 ,选择 工具 --> 扩展和更新 --> 联机,搜索 ...

  5. 从华为“鸿蒙”备胎看IT项目建设

    别误会啊,本文并不在讲大家在做IT项目建设的时候学华为做一个备胎系统,以防正主系统崩掉之后能够及时替换到备胎系统里面,不影响业务. 前段时间华为被美帝制裁,然后各家组织对华为各种限制.然而华为整体布局 ...

  6. JS 输出

    JS 输出 JavaScript 通常用于操作 HTML 元素. 操作 HTML 元素 如需从 JavaScript 访问某个 HTML 元素,您可以使用 document.getElementByI ...

  7. springboot架构下运用shiro后在configuration,通过@Value获取不到值,总是为null

    通过网上查找资料,是因为shiro的bean @Beanpublic LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return ...

  8. JavaScript 是如何运行的?

    摘要: 理解JS执行原理. 原文:JavaScript 是如何运行的? 作者:hengg Fundebug经授权转载,版权归原作者所有. 什么是JavaScript? 我们来确认一下JavaScrip ...

  9. Python虚拟环境导出包安装到另一台电脑的方法

    环境:Windows 版 Python Python 3.6.8可以用自带的命令建立虚拟环境,不用安装另外的如 virtualenv.virtualenvwrapper等工具. python -m v ...

  10. 06. Go 语言结构体

    Go语言结构体(struct) Go 语言通过用自定义的方式形成新的类型,结构体是类型中带有成员的复合类型.Go 语言使用结构体和结构体成员来描述真实世界的实体和实体对应的各种属性. Go 语言中的类 ...