Android 利用annotationProcessor生成Java代码

本文介绍了如何利用annotationProcessor和android-apt在Android中替代反射,提高性能。通过注解动态编译生成代码,解决MVP模式中presenter和model实例化的问题,减少性能损耗并简化model创建。示例展示了创建InstanceFactory类的过程,以及如何通过注解和泛型优化对象生成。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现在很多开源框架使用注解来解耦,但是利用反射来使用注解的方式很耗费性能,随着annotationProcessor和android-apt的出现通过注解根据反射机制动态编译生成代码的方式来解决在运行时不再使用发射机制,下面我们试着利用annotationProcessor和android-apt来替换反射的方式。

    public static Map<String, BasePresenter> createPresenters(BaseMethodCenter methodCenter, Class<?> clazz) {
        Map<String, BasePresenter> map = new HashMap<>();

        try {

            Annotation[] classAnnotations = clazz.getAnnotations();

            for(Annotation annotation : classAnnotations){

                if(annotation instanceof Presenter){
                    String[] classes = ((Presenter) annotation).value();

                    for(String className:classes){

                        Class presenterClass = Class.forName(MethodCenter.getPresenterPath()+"."+className);
                        Constructor<BasePresenter> constructor = presenterClass.getConstructor(BaseMethodCenter.class);
                        constructor.setAccessible(true);
                        BasePresenter presenter = constructor.newInstance(methodCenter);
                        map.put(className, presenter);

                        BaseLog.d(""+className+" added");
                    }

                }
            }

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            BaseLog.e("createPresenters NoSuchMethodException");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            BaseLog.e("createPresenters ClassNotFoundException");
        } catch (InvocationTargetException e) {
            e.printStackTrace();
            BaseLog.e("createPresenters InvocationTargetException");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            BaseLog.e("createPresenters IllegalAccessException");
        } catch (InstantiationException e) {
            e.printStackTrace();
            BaseLog.e("createPresenters InstantiationException");
        }

        return map;
    }
这个方法通过反射生成BasePresenter

@Presenter(value = {TestPresenter.class})
public class ViewMethodCenter extends MethodCenter {

ViewMethodCenter通过注解@Presenter生成TestPresenter实例,并将其保存在Map中,

这个是原先的设计,presenter实例创建采用了注解和反射,而model对象创建更容易出错

1.性能比直接调用要差,一个presenter实例看不出来,随着presenter的增多,性能的差距就开始显现

public abstract class BasePresenter<Model extends IContract.IModel>{
    
    Model mModel = createModel();
    ......

    public abstract Model createModel();
    
    ......
}

2.model在presenter的子类中生成,必须复写createModel抽象方法

利用annotationProcessor,首先创建一个java lib 的module,暂命名为apt

@AutoService(Processor.class)//自动生成 javax.annotation.processing.IProcessor 文件
@SupportedSourceVersion(SourceVersion.RELEASE_7)//java版本支持
@SupportedAnnotationTypes({//标注注解处理器支持的注解类型
        "com.pluginmvpm.annotation.InstanceFactory"
})
public class AnnotationProcessor extends AbstractProcessor {
    public Filer mFiler; //文件相关的辅助类
    public Elements mElements; //元素相关的辅助类
    public Messager mMessager; //日志相关的辅助类

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        mFiler = processingEnv.getFiler();
        mElements = processingEnv.getElementUtils();
        mMessager = processingEnv.getMessager();
        new InstanceProcessor().process(roundEnv, this);
        return true;
    }
}

创建AnnotationProcessor,

public class InstanceProcessor implements IProcessor {
    @Override
    public void process(RoundEnvironment roundEnv, AnnotationProcessor mAbstractProcessor) {
        String CLASS_NAME = "InstanceFactory";
        TypeSpec.Builder tb = classBuilder(CLASS_NAME).addModifiers(PUBLIC, FINAL).addJavadoc("@ 实例化工厂 此类由apt自动生成");
        MethodSpec.Builder methodBuilder1 = MethodSpec.methodBuilder("create").addAnnotation(MemoryCache.class)
                .addJavadoc("@此方法由apt自动生成")
                .returns(Object.class).addModifiers(PUBLIC, STATIC).addException(IllegalAccessException.class).addException(InstantiationException.class)
                .addParameter(Class.class, "mClass");

        List<ClassName> mList = new ArrayList<>();
        CodeBlock.Builder blockBuilder = CodeBlock.builder();
        blockBuilder.beginControlFlow(" switch (mClass.getSimpleName())");//括号开始
        try {
            for (TypeElement element : ElementFilter.typesIn(roundEnv.getElementsAnnotatedWith(InstanceFactory.class))) {
                mAbstractProcessor.mMessager.printMessage(Diagnostic.Kind.NOTE, "正在处理: " + element.toString());
                if (!Utils.isValidClass(mAbstractProcessor.mMessager, element)) return;
                ClassName currentType = ClassName.get(element);
                if (mList.contains(currentType)) continue;
                mList.add(currentType);
                blockBuilder.addStatement("case $S: return  new $T()", currentType.simpleName(), currentType);//初始化Presenter
            }
            blockBuilder.addStatement("default: return mClass.newInstance()");
            blockBuilder.endControlFlow();
            methodBuilder1.addCode(blockBuilder.build());
            tb.addMethod(methodBuilder1.build());
            JavaFile javaFile = JavaFile.builder(Utils.PackageName, tb.build()).build();// 生成源代码
            javaFile.writeTo(mAbstractProcessor.mFiler);// 在 app module/build/generated/source/apt 生成一份源代码
        } catch (FilerException e) {
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

InstanceProcessor主要用来生成Java代码,

public final class InstanceFactory {
  /**
   * @此方法由apt自动生成 */
  public static Object create(Class mClass) throws IllegalAccessException, InstantiationException {
     switch (mClass.getSimpleName()) {
      case "TestPresenter": return  new TestPresenter();
      default: return mClass.newInstance();
    }
  }
}

所有包含@InstanceFactory注解的类都会自动生成,例如TestPresenter

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.2.0'
    testCompile 'junit:junit:4.12'

    compile project(':lib')
    annotationProcessor project(':apt')
}

在gradle中关联apt工程,会自动编译生成InstanceFactory类

public class InstanceUtil {

    /**
     * 通过实例工厂去实例化相应类
     *
     * @param <T> 返回实例的泛型类型
     * @return
     */
    @TimeLog
    public static <T> T getInstance(Class clazz) {
        try {
            return (T) InstanceFactory.create(clazz);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}

封装成util使用

protected void initPresenter() {
        mPresenterMap = new HashMap<>();

        Annotation[] annotations = getClass().getAnnotations();
        for (Annotation annotation:annotations){
            if(annotation instanceof Presenter){
                Class[] presenters = ((Presenter) annotation).value();

                for(Class presenter : presenters){
                    InstanceUtil.getInstance(presenter);
                    BaseLog.d("presenter "+presenter.getName()+" added!");
                }

            }
        }

    }

改造后的代码,利用InstanceUtil创建presenter实例,解决了第一个问题

   public BasePresenter(){

        if (this.getClass().getGenericSuperclass() instanceof ParameterizedType &&
                ((ParameterizedType) (this.getClass().getGenericSuperclass())).getActualTypeArguments().length > 0) {
            Class modelClass = (Class) ((ParameterizedType) (this.getClass()
                    .getGenericSuperclass())).getActualTypeArguments()[0];
            model = InstanceUtil.getInstance(modelClass);
        }

        this.mMethodCenter = MethodCenter.getInstance();
        
        init();

    }

InstanceUtil还可以创建其他无参实例,拿到Presenter的泛型,直接创建出model,省去了model创建的部分,解决了第二个问题


总之,利用annotationProcessor生成的Java文件InstanceFactory类配合注解和泛型完美解决了MVP各层对象生成的问题


项目地址
https://github.com/jasonwang18/pluginMVPM


本文参考了T-MVP项目north大神的实例创建和分层的思想
https://github.com/north2016/T-MVP


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值