zoukankan      html  css  js  c++  java
  • Android自定义注解

    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);
    }
     
  • 相关阅读:
    CREATE AGGREGATE
    技术文档列表
    jQuery 判断表单中多个 input text 中至少有一个不为空
    Java实现 蓝桥杯 算法提高 奥运会开幕式
    Java实现 蓝桥杯 算法提高 最长滑雪道
    Java实现 蓝桥杯 算法提高 最长滑雪道
    Java实现 蓝桥杯 算法提高 最长滑雪道
    Java实现 蓝桥杯 算法提高 最大值路径
    Java实现 蓝桥杯 算法提高 最大值路径
    Java实现 蓝桥杯 算法提高 最大值路径
  • 原文地址:https://www.cnblogs.com/changeMsBlog/p/11217542.html
Copyright © 2011-2022 走看看