美文网首页
Android笔记-注解

Android笔记-注解

作者: roczheng | 来源:发表于2018-11-27 10:16 被阅读0次
    注解

    一、注解

    1.1注解分类

    注解分类.png

    1.2、示例

    1、定义注解

    public @interface Swordsman {
        String name() default "张三";//default设置默认值
        int age() default 23;
    }
    

    2、使用注解

        @Swordsman(name = "李四", age = 18)
        public class AnnotationTest {
        }
    

    3、定义运行时注解

    @Retention(RetentionPolicy.RUNTIME)
    public @interface Swordsman {
        String name() default "张三";//default设置默认值
        int age() default 23;
    }
    

    4、定义编译时注解

    @Retention(RetentionPolicy.CLASS)
    public @interface Swordsman {
        String name() default "张三";//default设置默认值
        int age() default 23;
    }
    

    @Retention来设定注解的保留策略,这 3 个策略的生命周期长度为 SOURCE <CLASS<RUNTIME。

    1.3注解处理器

    1.运行时注解处理器

    1.1定义运行时注解

    // 上面必须要有两个标识
    @Target(ElementType.FIELD)    // Target 放在哪里?哪里可以使用  FIELD 属性 TYPE 类上 METHOD 属性
    // 什么时候起作用 ,RUNTIME 运行时(程序运行中)  CLASS 代表的是编译时(打包的时候) SOURCE 编程阶段
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ViewById {// @interface 代表注解
        int value();
    }
    

    1.2定义注解处理的工具类

    public class ViewUtils {
        public static void inject(Activity activity) {
            // 1.获取所有的属性
            Field[] fields = activity.getClass().getDeclaredFields();
            // 2.过滤关于 ViewById 属性
            for (Field field : fields) {
                ViewById viewById = field.getAnnotation(ViewById.class);
                if (viewById != null) {
                    // 3.findViewById
                    View view = activity.findViewById(viewById.value());
                    field.setAccessible(true);//设置权限
                    // 4.反射注入
                    try {
                        // activity 属性所在类,view 代表的是属性的值
                        field.set(activity, view);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    1.3使用

    public class MainActivity extends BaseActivity {
        @ViewById(R.id.tv)
        private TextView tv;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            ViewUtils.inject(this);
            tv.setText("ViewById");
        }
    }
    
    

    2.编译时注解处理器

    ButterKnife用到了编译时注解,用apt生成代码,生成的类名×××Activity_ViewBinding,初始化时使用到了1次反射

    1、定义注解
    新建一个Java Library来专门存放注解,名为annotations

    @Retention(RetentionPolicy.CLASS)
    @Target(ElementType.FIELD)
    public @interface BindView {
        int value() default 1;
    }
    

    2、编写注解处理器
    再新建一个Java Library来存放注解处理器,这个Library名为processor。配置
    processor库的build.gradle:

    dependencies {
       ...
        compile project(':annotations  ')
    }
    

    注解处理器ClassProcessor,它继承AbstractProcessor

    public class ButterKnifeProcessor extends AbstractProcessor {
    
    //被注解处理工具调用
        @Override
        public synchronized void init(ProcessingEnvironment processingEnvironment) {
            super.init(processingEnvironment);
       
        }
    
        // 1. 指定处理的版本
        @Override
        public SourceVersion getSupportedSourceVersion() {
            return SourceVersion.latestSupported();
        }
    
        // 2. 给到需要处理的注解
        @Override
        public Set<String> getSupportedAnnotationTypes() {
            Set<String> types = new LinkedHashSet<>();
            for (Class<? extends Annotation> annotation : getSupportedAnnotations()) {
                types.add(annotation.getCanonicalName());
            }
            return types;
        }
    //必须指定的方法,指定这个注解处理器是注册给哪个注解的
    //返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称
        private Set<Class<? extends Annotation>> getSupportedAnnotations() {
            Set<Class<? extends Annotation>> annotations = new LinkedHashSet<>();
            // 需要解析的自定义注解 BindView  OnClick
            annotations.add(BindView.class.getCanonicalName);
            return annotations;
        }
    //process:相当于每个处理器的主函数main(),在这里写你的扫描、评估和处理注解的代码,以及生
    成Java文件
        @Override
        public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
     //提供注解处理器的方式报告错误消息,警告,等通知
            Messager messager = processingEnv.getMessager();
            for (Element element : roundEnvironment.getElementsAnnotatedWith(BindView.class)) {
                //判断当前注解是否为成员变量
                if (element.getKind() == ElementKind.FIELD) {
                    //打印出注解修饰的成员变量名称
                    messager.printMessage(Diagnostic.Kind.NOTE, "printMessage:" + element.toString());
                }
            }
            return true;
        }
    
    

    3、注册注解处理器
    使用服务文件来注册,简便方法使用Google开源的AutoService用来生成生成META-INF/services/javax.annotation.processing.Processor文件

    在File→Project Structure 搜索“auto-service”查找该库并添加

    使用

    @AutoService(Processor.class)
    public class ButterKnifeProcessor extends AbstractProcessor {
    ...
    }
    

    4、应用注解
    在主工程项目(app)中引用注解

    dependencies {
        ...
        compile project(':annotations ')
        compile project(':processor')
    }
    

    MainActivity中应用注解

      @BindView(value = R.id.tv)
       TextView tv_text;
    

    最后,先Clean Project再Make Project
    编译时会打印出@BindView注解修饰的成员变量名:tv_text

    5、使用android-apt插件
    两个作用:

    • 仅仅在编译时期去依赖注解处理器所在的函数库并进行工作,但不会打包到APK中。
    • 为注解处理器生成的代码设置好路径,以便Android Studio能够找到它。

    使用
    整个工程(Progect)的 build.gradle 中添加

       dependencies {
            ...
            classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
            
        }
    

    主工程项目(app)的 build.gradle 中以apt的方式引入注解处理器processor

    ...
    apply plugin: 'com.neenbedankt.android-apt'
    ...
    dependencies {
        ...
        //compile project(':processor')
        apt  project(':processor')
    }
    

    相关文章

      网友评论

          本文标题:Android笔记-注解

          本文链接:https://www.haomeiwen.com/subject/zvuiqqtx.html