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);
    }
     
  • 相关阅读:
    优秀的3D游戏开发系统和虚拟现实技术!
    C#反射实例(转)
    网易学院
    static 并发
    设计模式Strategy 策略模式
    1:统一建模语言UML轻松入门基本概念
    标准CSS 列表写法
    超级简单:ASP.NET Localization (本地化,多语言)
    js用escape()轻松搞定ajax post提交汉字的乱码问题
    认识.NET的集合
  • 原文地址:https://www.cnblogs.com/changeMsBlog/p/11217542.html
Copyright © 2011-2022 走看看