Android中应该了解的注解知识(Android进阶之光笔记)

2019-03-12  本文已影响0人  YangDxg

注解

本文讲解一些Android中用到的基本注解只是及ButterKnife和Dagger2原理

注解分类

注解分为标准注解和元注解

标准注解

元注解

元注解是用来注解其他的注解,从而创建新的注解

@Target注解取值是一个ElementType类型的数组,有以下几种取值
@Retention注解有三种类型,表示不同级别的保留策略

定义注解

基本定义

定义新的注解类型使用@interface关键字,和定义接口很像

    public @interface Swordsman{

    }

使用注解

    @Swordsman
    public class AnnotationTest{

    }

定义成员变量

注解只有成员变量,没有方法,注解的成员变量在注解定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型

    public @interface Swordsman {
        String name();

        int age();
    }

使用该注解时就应该为该注解的成员变量指定值

    @Swordsman(name = "张三",age = 23)
    public class AnnotationTest {

    }

定义成员变量时,使用default关键字为其指定默认值(使用默认值时就不需要传入参数了)

    public @interface Swordsman {
        String name() default "张三丰";

        int age() default 99;
    }

定义运行时注解

用@Retention来设定注解的保留策略,三种策略的生命周期长度为SOURCE《CLASS《RUNTIME,生命周期短的能起作用的地方,生命周期长的也一定能起作用.

    @Retention(RetentionPolicy.RUNTIME)
    public @interface Swordsman {
        String name() default "张三丰";

        int age() default 99;
    }

注解器处理

如果没有处理注解的工具,注解也不会有太大的作用,对于不同的注解有不同的注解处理器,注解器的处理标准

编写运行时注解处理器

运行时注解需要用到反射机制

    @Documented
    @Target(ElementType.METHOD)//定义方法
    @Retention(RetentionPolicy.RUNTIME)
    public @interface GET{
        String value() default "";
    }

上面代码是Retrofit中定义的@GET注解

    @GET(value = "http://baidu.com")
    public String getIpMsg() {
        return "";
    }

写一个简单的注解处理器

    public static void main(String [] args){
        Method[] methods = MainActivity.AnnotationTest.class.getDeclaredMethods();
        for (Method method : methods) {
            MainActivity.AnnotationTest.GET get = method.getAnnotation(MainActivity.AnnotationTest.GET.class);
            System.out.println(get.value());
        }
    }

getDeclaredMethods和getAnnotation俩个反射方法都属于AnnotatedElement接口,Class,Method和Filed等类都实现了该接口,调用getAnnotation方法返回指定类型的注解对象,也就是GET,调用GET的value方法返回从GET对象中提取的元素的值

编译时注解处理器
定义注解

创建Java Library来专门存放注解,Library名为annotations

这个注解类似于ButterKnife的@BindView

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

创建Java Library存放注解处理器,Library命名为processor,配置processor的build.gradle依赖annotations

apply plugin: 'java-library'

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    compile project(':annotations')
}

sourceCompatibility = "1.7"
targetCompatibility = "1.7"

编写注解处理器ClassProcessor

//Java7以后,使用下面俩个注解代替对应的方法,但考虑兼容问题,一般还是实现方法
//@SupportedSourceVersion(SourceVersion.RELEASE_8)
//@SupportedAnnotationTypes("com.yangdxg.annotation.cls.BindView")
public class ClassProcessor extends AbstractProcessor {

    /**
     * 被注解处理工具调用,输入processingEnvironment参数
     * processingEnvironment提供很多有用的工具类,如Elements,Types,Filer和Messager等
     * @param processingEnvironment
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
    }

    /**
     * 相当于每个处理器的祝函数main(),这里写扫描,评估和处理注解的代码以及生成java文件,
     * 出入参数roundEnviroment,可以查询出包含特定注解的被注解元素
     * @param set
     * @param roundEnvironment
     * @return
     */
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        return false;
    }

    /**
     * 必须指定的方法,指定这个注解处理器是注册给那个注解的,返回一个字符串的集合,包含本处理器想要处理的注解类型的合法全称
     * @return
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        LinkedHashSet<String> annotations = new LinkedHashSet<>();
        annotations.add(BindView.class.getCanonicalName());
        return annotations;
    }

    /**
     * 指定使用的Java版本
     * 一般返回 SourceVersion.latestSupported()
     *
     * @return
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
}

实现process方法

    @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方法来打印出注解修饰的成员变量的名称
                messager.printMessage(Diagnostic.Kind.NOTE, "printMessage:" + element.toString());
            }
        }
        return true;
    }
注册注解处理器

为了使用注解处理器,需要用一个服务文件来注册,创建这个服务文件

可以使用AutoService帮助完成上面步骤
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    compile project(':annotations')
    compile 'com.google.auto.service.auto-service:1.0-rc2'
}
@AutoService(Processor.class)
public class ClassProcessor extends AbstractProcessor {
    compile project(':annotations')
    compile project(':processor')
    @BindView(value = R.id.tv_text)
    TextView mTextView;
注: printMessage:mTextView
使用android-apt插件

应用了processor库,但注解处理器只在编译处理期间需要用到,编译处理完后就没有实际作用了,而主工程添加了这个库会引入很多不必要的文件,为了解决这个问题引入插件android-apt,它的作用是

dependencies {
    annotationProcessor ':processor'

依赖注入的原理

控制反转

为了解决对象之间耦合度过高的问题,提出了IoC理论,用来实现对象之间的解耦,即控制反转,借助第三方实现具有依赖关系的对象之间的解耦

依赖注入

控制反转是获得依赖对象的过程被反转了,控制反转之后,获得依赖对象的过程由自身管理变为由IoC容器主动注入

依赖注入的实现方式

构造方法注入
public class Car{
    private Engine mEngine;
    public Car(Engine engine){
        this.mEngine=engine;
    }
}
Setter方法注入
public class Car{
    private Engine mEngine;
    public void set(Engine engine){
        this.mEngine=engine;
    }
}
接口注入
public interface ICar{
    public void setEngine(Engine engine);
}

Car类实现ICar

public class Car implement ICar{
    private Engine mEngine;
    public void setEngine(Engine engine){
        this.mEngine=engine;
    }
}

通过以上三种方式,Car和Engine解耦合了,Car不关心Engine的实现,即使Engine的类型变换了,Car也不需要做修改

上一篇下一篇

猜你喜欢

热点阅读