使用编译期注解对Activity和Fragment动态注入参数

2020-02-08  本文已影响0人  有没有口罩给我一个

在我们从上一个页面跳转到下一个页面需要携带数据给下一个页面,我们是这样获取生个页面的数据:

 intent.putExtra("id",1);
 getIntent().getStringExtra("id")

上面代码我相信大家也是会犯的错误,参数类型安全,因为这些参数的类型需要人工维护,容易造成参数类型安全频频出现。所以就有了这篇文章,自动注入参数现在有很多框架也有,像ARouter和ButterKife也有使用编译器生成代码自动注入参数,只有用法不一样。

按照我们以往的写法:

//必须和Activity同包
public class XXXActivity$$Parameter implements ParameterInject {
@Override
public void inject(Object target) {
    MainActivity mainActivity = (MainActivity) target;
    mainActivity.getIntent().getSerializableExtra("");
    ArrayList<Parcelable> parcelableArrayListExtra = mainActivity.getIntent().getParcelableArrayListExtra("");
    mainActivity.age = mainActivity.getIntent().getBundleExtra("").getInt("");
    }
}

所以我们需要按照上面的代码,通过注解处理器生成我们想要的代码,然后通过inject方法注入参数。

public interface ParameterInject {
    void inject(Object target);
}

ParameterInject 类是我们通过注解生成类必须实现的接口,因为我们后面要通过反射创建生成类的对象,而且生成的类名是有一定的规则,方便我们快速的找到该类,需要注意的是,生成的类必须和需要注入参数的类是同一个包下的,避免方法属性出现问题。

@AutoService(Processor.class)
@SupportedAnnotationTypes({Constants.PARAMETER_ANNOTATION_TYPES})
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class ParameterProcessor extends AbstractProcessor {

//临时map存储,用来存放@Parameter注解的属性集合,生成类文件时遍历
//key : 类节点  value:被@Parameter注解的属性集合
private Map<TypeElement, List<Element>> tempPrameterMap = new ConcurrentHashMap<>();


@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
    super.init(processingEnvironment);
    elementUtils = processingEnvironment.getElementUtils();
    typeUtils = processingEnvironment.getTypeUtils();
    messager = processingEnvironment.getMessager();
    filer = processingEnvironment.getFiler();
    activityTypeMirror = elementUtils.getTypeElement(Constants.ACTIVITY).asType();
    appFragmentTypeMirror = elementUtils.getTypeElement(Constants.APP_FRAGMENT).asType();
    androidXFragmentTypeMirror = elementUtils.getTypeElement(Constants.ANDROIDX_FRAGMENT).asType();
    parcelableTypeMirror = elementUtils.getTypeElement(Constants.PARCELABLE).asType();
    serializableTypeMirror = elementUtils.getTypeElement(Constants.SERIALIZABLE).asType();
}

/**
 * 相当于main函数,开始处理注解
 * 注解处理器的核心方法,处理具体的注解,生成Java文件
 *
 * @param set              使用了支持处理注解的节点集合(类 上面写了注解)
 * @param roundEnvironment 当前或是之前的运行环境,可以通过该对象查找找到的注解。
 * @return true 表示后续处理器不会再处理(已经处理完成)
 */
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
    if (set.isEmpty()) return true;

    Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Parameter.class);
    if (!EmptyUtils.isEmpty(elements)) {
        valueOfParameter(elements);
        createParameterFile();
    }

    return true;
}

private void createParameterFile() {
    if (tempPrameterMap.isEmpty()) return;

    TypeElement typeElement = elementUtils.getTypeElement(Constants.PARAMETER_LOAD);

    ParameterSpec parameterSpec = ParameterSpec.builder(TypeName.OBJECT, Constants.PARAMETER_NAMR).build();


    for (Map.Entry<TypeElement, List<Element>> entry : tempPrameterMap.entrySet()) {
        //activity,Fragment or other
        TypeElement otherTypeElement = entry.getKey();
        ClassName otherClassName = ClassName.get(otherTypeElement);
        TypeMirror otherType = otherTypeElement.asType();


        MethodSpec.Builder builder = MethodSpec.methodBuilder(Constants.PARAMETER_METHOD_NAME)
                .addParameter(parameterSpec)
                .addModifiers(Modifier.PUBLIC)
                .returns(TypeName.VOID)
                //MainActivity t = (MainActivity) target;
                .addStatement("$T t = ($T)$N", otherClassName,
                        otherClassName, Constants.PARAMETER_NAMR);

        //该类下的所有被@Parameter注解的属性
        List<Element> elements = entry.getValue();

        for (Element element : elements) {
            //被@Parameter注解属性信息
            TypeMirror typeMirror = element.asType();
            int type = typeMirror.getKind().ordinal();
            // 被@Parameter注解的属性名
            String filedName = element.getSimpleName().toString();


            // @Parameter注解获取属性名
            String annotationValue = element.getAnnotation(Parameter.class).name();
            annotationValue = EmptyUtils.isEmpty(annotationValue) ? filedName : annotationValue;

            //如:t.age = target.getIntent().getStringExtra("age", 1);
            String finalValue = "t" + "." + annotationValue;


            StringBuilder buffer = new StringBuilder();
            if (typeUtils.isSubtype(otherType, activityTypeMirror)) {//activity
                if (type == TypeKind.INT.ordinal()) {
                    buffer.append(finalValue).append(" =  t.getIntent().");
                    buffer.append("getIntExtra($S,").append(finalValue).append(")");
                } else if (type == TypeKind.BOOLEAN.ordinal()) {
                    buffer.append(finalValue).append(" =  t.getIntent().");
                    buffer.append("getBooleanExtra($S,").append(finalValue).append(")");
                } else if (typeMirror.toString().equalsIgnoreCase(Constants.STRING)) {
                    buffer.append(finalValue).append(" =  t.getIntent().");
                    buffer.append("getStringExtra($S)");
                } else if (type == TypeKind.DOUBLE.ordinal()) {
                    buffer.append(finalValue).append(" =  t.getIntent().");
                    buffer.append("getDoubleExtra($S,").append(finalValue).append(")");
                } else if (type == TypeKind.FLOAT.ordinal()) {
                    buffer.append(finalValue).append(" =  t.getIntent().");
                    buffer.append("getFloatExtra($S,").append(finalValue).append(")");
                } else if (type == TypeKind.LONG.ordinal()) {
                    buffer.append(finalValue).append(" =  t.getIntent().");
                    buffer.append("getLongExtra($S,").append(finalValue).append(")");
                } else if (typeUtils.isSubtype(element.asType(), parcelableTypeMirror)) {//Parcelable的子类
                    buffer.append(finalValue).append(" =  t.getIntent().");
                    buffer.append("getParcelableExtra($S)");
                } else if (typeUtils.isSubtype(element.asType(), serializableTypeMirror)) {//Serializable的实现类
                    messager.printMessage(Diagnostic.Kind.NOTE, element.asType().toString());
                    buffer.append(finalValue).append(" = ");//t.finalValue
                    //int[]、 String[]、Bundle、ArrayList和Map实现了Serializable,我们只需要强转即可
                    buffer.append("(").append(element.asType().toString()).append(")");
                    buffer.append("t.getIntent().");
                    buffer.append("getSerializableExtra($S)");
                }
                builder.addStatement(buffer.toString(), annotationValue);
            } else if (typeUtils.isSubtype(otherType, appFragmentTypeMirror) ||
                    typeUtils.isSubtype(otherType, androidXFragmentTypeMirror)) {//fragment
                buffer.append(finalValue).append(" =  t.getArguments().");
                if (type == TypeKind.INT.ordinal()) {
                    buffer.append("getInt($S,").append(finalValue).append(")");
                } else if (type == TypeKind.BOOLEAN.ordinal()) {
                    buffer.append("getBoolean($S,").append(finalValue).append(")");
                } else if (typeMirror.toString().equalsIgnoreCase(Constants.STRING)) {
                    buffer.append("getString($S,").append(finalValue).append(")");
                }
                builder.addStatement(buffer.toString(), annotationValue);
            }
        }
        String finalClassName = otherClassName.simpleName() + Constants.PARAMETER_FILE_NAME;
        messager.printMessage(Diagnostic.Kind.NOTE, otherClassName.packageName() + "生成parameter注解的类名 >>> " + finalClassName);

        try {
            JavaFile.builder(
                    otherClassName.packageName(),
                    TypeSpec.classBuilder(finalClassName)
                            .addModifiers(Modifier.PUBLIC)
                            .addSuperinterface(ClassName.get(typeElement))
                            .addMethod(builder.build()).build()
            ).build().writeTo(filer);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

private void valueOfParameter(Set<? extends Element> elements) {
    for (Element element : elements) {
        TypeElement typeElement = (TypeElement) element.getEnclosingElement();
        if (tempPrameterMap.containsKey(typeElement)) {
            tempPrameterMap.get(typeElement).add(element);
        } else {
            CopyOnWriteArrayList<Element> files = new CopyOnWriteArrayList<>();
            files.add(element);
            tempPrameterMap.put(typeElement, files);
        }
    }
}
}

注解处理代码也不多,需要注意的是在生成类型时int[]、 String[]、Bundle、ArrayList和Map实现了Serializable,我们只需要强转即可。

如何使用?

public class Order_MainActivity extends AppCompatActivity {

@Parameter
int age = 1;

@Parameter
String name = "";

@Parameter
User user;

@Parameter(name = "users")
ArrayList<User> users;

@Parameter
Order order;

@Parameter
ArrayList<Order> orders;

@Parameter
Bundle bundle;

@Parameter
String[] args;


@Parameter
int[] ints;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_order__main);
    ParameterManager.getInstance().inject(this);
    Log.e("tag", "age >>> " + age + " users>>>" +
            users + " >>> " + user + " >>> " + order + "  >>>  " + orders + " >>> " + bundle.getInt("age"));
}

}

最后生成的类:

public class Order_MainActivity$$Parameter implements ParameterInject {
public void inject(Object target) {
    Order_MainActivity t = (Order_MainActivity) target;
    t.age = t.getIntent().getIntExtra("age", t.age);
    t.name = t.getIntent().getStringExtra("name");
    t.user = t.getIntent().getParcelableExtra("user");
    t.users = (java.util.ArrayList<com.wfy.common.User>) t.getIntent().getSerializableExtra("users");
    t.order = (com.wfy.common.Order) t.getIntent().getSerializableExtra("order");
    t.orders = (java.util.ArrayList<com.wfy.common.Order>) t.getIntent().getSerializableExtra("orders");
    t.bundle = t.getIntent().getParcelableExtra("bundle");
    t.args = (java.lang.String[]) t.getIntent().getSerializableExtra("args");
    t.ints = (int[]) t.getIntent().getSerializableExtra("ints");
    }
}

总结

上一篇下一篇

猜你喜欢

热点阅读