Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
329 lines (264 sloc) 10.8 KB
title tags date keywords
自定义注解,打造自己的框架 (中篇)
Android
2019-12-01 09:42:27 -0800
自定义注解
Annotation
AutoService
AbstractProcessor
反射
javapoet

该系列介绍自定义注解,完成如下功能。

  • @BindView 代替 findViewById
  • @ClickResponder 代替 setOnClickListener
  • @LongClickResponder 代替 setOnLongClickListener
  • @IntentValue 代替 getIntent().getXXX
  • @UriValue 代替 getQueryParameter
  • @BroadcastResponder 代替 registerReceiver
  • @RouterModule、@RouterPath 来进行反依赖传递调用 该系列源码在https://github.com/huangyuanlove/AndroidAnnotation 使用编译时注解,生成辅助类来完成这些操作,尽量少的使用的反射功能。

本章先介绍 javapoet 和一丢丢反射相关的东西

javapoet

用来辅助生成java代码的库,可以看这里,有特别详细的示例。大致过了一遍,如下所示

public class TestJavaPoet {
    public static void main(String[] args) {
        TypeSpec clazz = clazz(builtinTypeField(),          // int
                arrayTypeField(),            // int[]
                refTypeField(),              // File
                typeField(),                 // T
                parameterizedTypeField(),    // List<String>
                wildcardTypeField(),         // List<? extends String>
                constructor(),               // 构造函数
                method(code()));             // 普通方法
        JavaFile javaFile = JavaFile.builder("com.huangyuanlove.view_inject_compiler.test", clazz).build();

        System.out.println(javaFile.toString());
    }

    /**
     * `public abstract class Clazz<T> extends String implements Serializable, Comparable<String>, Comparable<? extends String> {
     * ...
     */
    private static TypeSpec clazz(FieldSpec builtinTypeField, FieldSpec arrayTypeField, FieldSpec refTypeField,
                                 FieldSpec typeField, FieldSpec parameterizedTypeField, FieldSpec wildcardTypeField,
                                 MethodSpec constructor, MethodSpec methodSpec) {
        return TypeSpec.classBuilder("Clazz")
                // 限定符
                .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
                // 泛型
                .addTypeVariable(TypeVariableName.get("T"))

                // 继承与接口
                .superclass(String.class)
                .addSuperinterface(Serializable.class)
                .addSuperinterface(ParameterizedTypeName.get(Comparable.class, String.class))
                .addSuperinterface(ParameterizedTypeName.get(ClassName.get(Map.class),
                        TypeVariableName.get("T"),
                        WildcardTypeName.subtypeOf(String.class)))

                // 初始化块
                .addStaticBlock(CodeBlock.builder().build())
                .addInitializerBlock(CodeBlock.builder().build())

                // 属性
                .addField(builtinTypeField)
                .addField(arrayTypeField)
                .addField(refTypeField)
                .addField(typeField)
                .addField(parameterizedTypeField)
                .addField(wildcardTypeField)

                // 方法 (构造函数也在此定义)
                .addMethod(constructor)
                .addMethod(methodSpec)

                // 内部类
                .addType(TypeSpec.classBuilder("InnerClass").build())

                .build();
    }

    /**
     * 内置类型
     */
    private static FieldSpec builtinTypeField() {
        // private int mInt;
        return FieldSpec.builder(int.class, "mInt", Modifier.PRIVATE).build();
    }

    /**
     * 数组类型
     */
    private static FieldSpec arrayTypeField() {
        // private int[] mArr;
        return FieldSpec.builder(int[].class, "mArr", Modifier.PRIVATE).build();
    }

    /**
     * 需要导入 import 的类型
     */
    private static FieldSpec refTypeField() {
        // private File mRef;
        return FieldSpec.builder(File.class, "mRef", Modifier.PRIVATE).build();
    }

    /**
     * 泛型
     */
    private static FieldSpec typeField() {
        // private File mT;
        return FieldSpec.builder(TypeVariableName.get("T"), "mT", Modifier.PRIVATE).build();
    }

    /**
     * 参数化类型
     */
    private static FieldSpec parameterizedTypeField() {
        // private List<String> mParameterizedField;
        return FieldSpec.builder(ParameterizedTypeName.get(List.class, String.class),
                "mParameterizedField",
                Modifier.PRIVATE)
                .build();
    }

    /**
     * 通配符参数化类型
     */
    private static FieldSpec wildcardTypeField() {
        // private List<? extends String> mWildcardField;
        return FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(List.class),
                WildcardTypeName.subtypeOf(String.class)),
                "mWildcardField",
                Modifier.PRIVATE)
                .build();
    }

    /**
     * 构造函数
     */
    private static MethodSpec constructor() {
        return MethodSpec.constructorBuilder()
                .addModifiers(Modifier.PUBLIC)
                .build();
    }

    /**
     * `@Override
     * public <T> Integer method(String string, T t, Map<Integer, ? extends T> map) throws IOException, RuntimeException {
     * ...
     * }`
     *
     */
    private static MethodSpec method(CodeBlock codeBlock) {
        return MethodSpec.methodBuilder("method")
                .addAnnotation(Override.class)
                .addTypeVariable(TypeVariableName.get("T"))
                .addModifiers(Modifier.PUBLIC)
                .returns(int.class)
                .addParameter(String.class, "string")
                .addParameter(TypeVariableName.get("T"), "t")
                .addParameter(ParameterizedTypeName.get(ClassName.get(Map.class),
                        ClassName.get(Integer.class),
                        WildcardTypeName.subtypeOf(TypeVariableName.get("T"))),
                        "map")
                .addException(IOException.class)
                .addException(RuntimeException.class)
                .addCode(codeBlock)
                .build();
    }

    /**
     * ‘method’ 方法中的具体语句
     */
    private static CodeBlock code() {
        return CodeBlock.builder()
                .addStatement("int foo = 1")
                .addStatement("$T bar = $S", String.class, "a string")

                // Object obj = new HashMap<Integer, ? extends T>(5);
                .addStatement("$T obj = new $T(5)",
                        Object.class, ParameterizedTypeName.get(ClassName.get(HashMap.class),
                                ClassName.get(Integer.class),
                                WildcardTypeName.subtypeOf(TypeVariableName.get("T"))))

                // method(new Runnable(String param) {
                //   @Override
                //   void run() {
                //   }
                // });
                .addStatement("baz($L)", TypeSpec.anonymousClassBuilder("$T param", String.class)
                        .superclass(Runnable.class)
                        .addMethod(MethodSpec.methodBuilder("run")
                                .addAnnotation(Override.class)
                                .returns(TypeName.VOID)
                                .build())
                        .build())

                // for
                .beginControlFlow("for (int i = 0; i < 5; i++)")
                .endControlFlow()

                // while
                .beginControlFlow("while (false)")
                .endControlFlow()

                // do... while
                .beginControlFlow("do")
                .endControlFlow("while (false)")

                // if... else if... else...
                .beginControlFlow("if (false)")
                .nextControlFlow("else if (false)")
                .nextControlFlow("else")
                .endControlFlow()

                // try... catch... finally
                .beginControlFlow("try")
                .nextControlFlow("catch ($T e)", Exception.class)
                .addStatement("e.printStackTrace()")
                .nextControlFlow("finally")
                .endControlFlow()

                .addStatement("return 0")
                .build();
    }

这样就省去了我们自己手动评价代码块的麻烦,提高效率,并且也比较容易查错。

反射

这玩意说起来可就长了,这里只做示例

一个Person类

package com.huangyuanlove;

public class Person {
    private int age;
    public String name;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddress(){
        return "getAddress without param";
    }

    private String getAddress(String zipCode){
        return "getAddress with param:" + zipCode;
    }

    private Person() {
    }
}

玩一下反射

package com.huangyuanlove;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Main {

    public static void main(String[] args) {

        try {
            //如果没有对应类的依赖的话(不能直接import),可以用Class.forName
            //Class personClass = Class.forName("com.huangyuanlove.Person");
            Class<Person> personClass = Person.class;

            //调用私有无参构造方法创建对象
            Constructor<Person> personConstructor = personClass.getDeclaredConstructor();
            personConstructor.setAccessible(true);
            Person person = personConstructor.newInstance();
            //反射获取公共方法并调用
            Method getAddressWithoutParamMethod = personClass.getMethod("getAddress");
            System.out.println( getAddressWithoutParamMethod.invoke(person));

            //反射获取私有方法并调用
            Method getAddressMethod = personClass.getDeclaredMethod("getAddress", String.class);
            getAddressMethod.setAccessible(true);
            System.out.println(getAddressMethod.invoke(person, "zipCode"));

            //反射获取私有字段并赋值
            Field ageField =  personClass.getDeclaredField("age");
            ageField.setAccessible(true);
            ageField.set(person,11);
            System.out.println(person.getAge());

            //反射获取私有静态方法并调用
            Method sayHiMethod = personClass.getDeclaredMethod("saySomething",String.class);
            sayHiMethod.setAccessible(true);
            sayHiMethod.invoke(null,"reflect");


        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

以上

You can’t perform that action at this time.