Android注解笔记

2019-08-07  本文已影响0人  R7_Perfect

注解(Annotation)

元注解

@Target 表明我们注解可以出现的地方。是一个ElementType枚举

类型 说明
ElementType.TYPE 接口、类、枚举、注解
ElementType.FIELD 字段、枚举的常量
ElementType.METHOD 方法
ElementType.PARAMETER 方法参数
ElementType.CONSTRUCTOR 构造函数
ElementType.LOCAL_VARIABLE 局部变量
ElementType.ANNOTATION_TYPE 注解
ElementType.PACKAGE

@Retention 这个注解的的存活时间

类型 说明
RetentionPolicy.SOURCE 注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃
RetentionPolicy.CLASS 注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期
RetentionPolicy.RUNTIME 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在

@Document 表明注解可以被javadoc此类的工具文档化
@Inherited 是否允许子类继承该注解,默认为false

反射相关

    /**
     * 包名加类名
     */
    public String getName();
    /**
     * 类名
     */
    public String getSimpleName();
    /**
     * 返回当前类和父类层次的public构造方法
     */
    public Constructor<?>[] getConstructors();
    /**
     * 返回当前类所有的构造方法(public、private和protected)
     * 不包括父类
     */
    public Constructor<?>[] getDeclaredConstructors();
    /**
     * 返回当前类所有public的字段,包括父类
     */
    public Field[] getFields();
    /**
     * 返回当前类所有申明的字段,即包括public、private和protected,
     * 不包括父类
     */
    public native Field[] getDeclaredFields();
    /**
     * 返回当前类所有public的方法,包括父类
     */
    public Method[] getMethods();
    /**
     * 返回当前类所有的方法,即包括public、private和protected,
     * 不包括父类
     */
    public Method[] getDeclaredMethods();
    /**
     * 获取局部或匿名内部类在定义时所在的方法
     */
    public Method getEnclosingMethod();
    /**
     * 获取当前类的包
     */
    public Package getPackage();
    /**
     * 获取当前类的包名
     */
    public String getPackageName$();
    /**
     * 获取当前类的直接超类的 Type
     */
    public Type getGenericSuperclass();
    /**
     * 返回当前类直接实现的接口.不包含泛型参数信息
     */
    public Class<?>[] getInterfaces();
    /**
     * 返回当前类的修饰符,public,private,protected
     */
    public int getModifiers();
//==========================注解相关===========================================
    /**
     * 指定类型的注释是否存在于此元素上
     */
    default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
        return getAnnotation(annotationClass) != null;
    }
    /**
     * 返回该元素上存在的指定类型的注解
     */
    <T extends Annotation> T getAnnotation(Class<T> annotationClass);
    /**
     * 返回该元素上存在的所有注解
     */
    Annotation[] getAnnotations();
    /**
     * 返回该元素指定类型的注解
     */
    default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
        return AnnotatedElements.getDirectOrIndirectAnnotationsByType(this, annotationClass);
    }
    /**
     * 返回直接存在与该元素上的所有注释(父类里面的不算)
     */
    default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
        Objects.requireNonNull(annotationClass);
        // Loop over all directly-present annotations looking for a matching one
        for (Annotation annotation : getDeclaredAnnotations()) {
            if (annotationClass.equals(annotation.annotationType())) {
                // More robust to do a dynamic cast at runtime instead
                // of compile-time only.
                return annotationClass.cast(annotation);
            }
        }
        return null;
    }
    /**
     * 返回直接存在该元素岸上某类型的注释
     */
    default <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
        return AnnotatedElements.getDirectOrIndirectAnnotationsByType(this, annotationClass);
    }
    /**
     * 返回直接存在与该元素上的所有注释
     */
    Annotation[] getDeclaredAnnotations();

运行时注解

ButterKnife例子:

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

public class ButterKnifeProcess {
    /**
     * 绑定Activity
     */
    public static void bind(final Activity activity) {
        Class annotationParent = activity.getClass();
        Field[] fields = annotationParent.getDeclaredFields();
        Method[] methods = annotationParent.getDeclaredMethods();
        // OnClick
        // 找到类里面所有的方法
        for (final Method method : methods) {
            //找到添加了OnClick注解的方法
            OnClick clickMethod = method.getAnnotation(OnClick.class);
            if (clickMethod != null && clickMethod.value().length != 0) {
                for (int id : clickMethod.value()) {
                    final View view = activity.findViewById(id);
                    view.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            try {
                                method.invoke(activity, view);
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            }
        }
    }
}

public class MainActivity extends AppCompatActivity {
    //自动绑定view
    @BindView(R.id.text_abstract_processor)
    TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnifeProcess.bind(this);
    }
}

编译时注解

注解处理器类

/**
     * 每个Annotation Processor必须有一个空的构造函数。
     * 编译期间,init()会自动被注解处理工具调用,并传入ProcessingEnvironment参数,
     * 通过该参数可以获取到很多有用的工具类(Element,Filer,Messager等)
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
    }

    /**
     * 用于指定自定义注解处理器(Annotation Processor)是注册给哪些注解的(Annotation),
     * 注解(Annotation)指定必须是完整的包名+类名
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return super.getSupportedAnnotationTypes();
    }

    /**
     * 用于指定你的java版本,一般返回:SourceVersion.latestSupported()
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    /**
     * Annotation Processor扫描出的结果会存储进roundEnvironment中,可以在这里获取到注解内容,编写你的操作逻辑。
     * 注意:process()函数中不能直接进行异常抛出,否则程序会异常崩溃
     */
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        return false;
    }
Element子类 解释
TypeElement 类或接口元素
VariableElement 字段、enum常量、方法或构造方法参数、局部变量或异常参数元素
ExecutableElement 类或接口的方法、构造方法,或者注解类型元素
PackageElement 包元素
TypeParameterElement 类、接口、方法或构造方法元素的泛型参数
/**
     * 返回此元素定义的类型,int,long这些
     */
    TypeMirror asType();

    /**
     * 返回此元素的种类:包、类、接口、方法、字段
     */
    ElementKind getKind();

    /**
     * 返回此元素的修饰符:public、private、protected
     */
    Set<Modifier> getModifiers();

    /**
     * 返回此元素的简单名称(类名)
     */
    Name getSimpleName();

    /**
     * 返回封装此元素的最里层元素。
     * 如果此元素的声明在词法上直接封装在另一个元素的声明中,则返回那个封装元素;
     * 如果此元素是顶层类型,则返回它的包;
     * 如果此元素是一个包,则返回 null;
     * 如果此元素是一个泛型参数,则返回 null.
     */
    Element getEnclosingElement();

    /**
     * 返回此元素直接封装的子元素
     */
    List<? extends Element> getEnclosedElements();

    /**
     * 返回直接存在于此元素上的注解
     * 要获得继承的注解,可使用 getAllAnnotationMirrors
     */
    List<? extends AnnotationMirror> getAnnotationMirrors();

    /**
     * 返回此元素上存在的指定类型的注解
     */
    <A extends Annotation> A getAnnotation(Class<A> var1);
注解解析器帮助类 解释
Elements 一个用来处理Element的工具类
Types 一个用来处理TypeMirror的工具类
Filer 用于创建文件(比如创建class文件)
Messager 用于输出,类似printf函数

实例

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
public @interface JsBridgeMethod {
    String value() default "";
}

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface JsBridgeApi {
    String value() default "";
}

@AutoService(Processor.class)
public class JsBridgeAnnoProcessor extends AbstractProcessor {
    private Elements mElementUtils; //基于元素进行操作的工具方法
    private Filer mFileCreator;     //代码创建者
    private Messager mMessager;     //日志,提示者,提示错误、警告
    private Map<String, HashMap<String, String>> exposedMethodsByName = new HashMap<>();//做缓存用
    private Map<String, String> classNameByJsApiName = new HashMap<>();//类名存储
    private String packageName;

    @Override
    public synchronized void init(final ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        mElementUtils = processingEnv.getElementUtils();
        mFileCreator = processingEnv.getFiler();
        mMessager = processingEnv.getMessager();
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types = new LinkedHashSet<>();
        types.add(JsBridgeMethod.class.getCanonicalName());
        return types;
    }

 @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        final Set<? extends Element> elementsAnnotatedWith =
                roundEnvironment.getElementsAnnotatedWith(JsBridgeMethod.class);
        for (Element element : elementsAnnotatedWith) {
            ExecutableElement executableElement = (ExecutableElement) element;
            final TypeElement typeElement = (TypeElement) executableElement.getEnclosingElement();
            final String s = mElementUtils.getPackageOf(typeElement).getQualifiedName().toString();

            mMessager.printMessage(Diagnostic.Kind.NOTE, "package===>" + s);
            if (!s.equals(packageName)) {
                packageName = s;
            }

            final JsBridgeApi jsBridgeApi = typeElement.getAnnotation(JsBridgeApi.class);
            if (jsBridgeApi != null) {
                String jsBridgeApiName = jsBridgeApi.value();
                if ("".equals(jsBridgeApiName)) {
                    jsBridgeApiName = typeElement.getSimpleName().toString();
                }
                //完整类名
                final String qualifiedName = typeElement.getQualifiedName().toString();

                JsBridgeMethod jsBridgeMethod =
                        executableElement.getAnnotation(JsBridgeMethod.class);
                //注解上的js方法名
                String jsMethodName = jsBridgeMethod.value();

                //真实方法名
                final String methodName = executableElement.getSimpleName().toString();

                if ("".equals(jsMethodName)) {
                    jsMethodName = methodName;
                }

                classNameByJsApiName.put(jsBridgeApiName, qualifiedName);

                //查询缓存中有无存过这个类
                HashMap<String, String> methodsByApi;
                if (!exposedMethodsByName.containsKey(jsBridgeApiName)) {
                    methodsByApi = new HashMap<>();
                    exposedMethodsByName.put(jsBridgeApiName, methodsByApi);
                } else {
                    methodsByApi = exposedMethodsByName.get(jsBridgeApiName);
                }
                methodsByApi.put(jsMethodName, methodName);
            }
        }

        writeJava();
        return true;
    }

private void writeJava() {
        final ParameterizedTypeName hashMapType =
                ParameterizedTypeName.get(ClassName.get(HashMap.class), ClassName.get(String.class),
                        ClassName.get(Method.class));

        final MethodSpec.Builder methodBuild = MethodSpec.methodBuilder("register")
                .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                .returns(void.class)
                .addParameter(ParameterizedTypeName.get(ClassName.get(Map.class),
                        ClassName.get(String.class), hashMapType), "exposedMethods");

        final CodeBlock.Builder codeBuilder = CodeBlock.builder();
        for (String jsApiName : exposedMethodsByName.keySet()) {

            String className = classNameByJsApiName.get(jsApiName);
            //分割 dot 需要转义
            final String[] split = className.split("\\.");
            String simpleName = split[split.length - 1];

            String methodMapName = "mMethodsMap" + simpleName;
            codeBuilder.add("HashMap<String, Method> $L = new HashMap<>();\n", methodMapName);
            final HashMap<String, String> methodNameByJsName = exposedMethodsByName.get(jsApiName);
            for (String jsName : methodNameByJsName.keySet()) {
                codeBuilder.add(methodMapName
                                + ".put($S,$L.class.getMethod($S,com.sample.jsbridgelibrary.webView.WebViewFragmentWrapper.class,String.class,com.sample.jsbridgelibrary.bridge.Callback.class));\n",
                        jsName, className, methodNameByJsName.get(jsName));
            }

            codeBuilder.add("exposedMethods.put($S,$L);\n", jsApiName, methodMapName);
        }

        final MethodSpec registerMethod = methodBuild.beginControlFlow("try")
                .addStatement(codeBuilder.build())
                .nextControlFlow("catch ($T e)", Exception.class)
                .addStatement("e.printStackTrace()")
                .endControlFlow()
                .build();

        TypeSpec JsBridgeRegister = TypeSpec.classBuilder("JsBridgeRegister")
                .addModifiers(Modifier.PUBLIC)
                .addMethod(registerMethod)
                .build();

        mMessager.printMessage(Diagnostic.Kind.NOTE, "javaFile package===>" + packageName);
        JavaFile javaFile = JavaFile.builder(packageName, JsBridgeRegister).build();
        //        mMessager.printMessage(Diagnostic.Kind.NOTE, javaFile.toString());
        try {
            javaFile.writeTo(mFileCreator);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

参考https://blog.csdn.net/wuyuxing24/article/details/81139846

上一篇下一篇

猜你喜欢

热点阅读