温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Android APT怎么使用

发布时间:2021-12-18 16:17:35 来源:亿速云 阅读:228 作者:iii 栏目:移动开发

本篇内容主要讲解“Android APT怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Android APT怎么使用”吧!

安卓AOP三剑客: APT, AspectJ, Javassist

Android APT怎么使用

Android APT

APT(Annotation Processing Tool 的简称),可以在代码编译期解析注解,并且生成新的 Java  文件,减少手动的代码输入。现在有很多主流库都用上了 APT,比如 Dagger2, ButterKnife, EventBus3 等

代表框架:

  • DataBinding

  • Dagger2

  • ButterKnife

  • EventBus3

  • DBFlow

  • AndroidAnnotation

使用姿势

1,在android工程中,创建一个java的Module,写一个类继承AbstractProcessor

@AutoService(Processor.class) // javax.annotation.processing.IProcessor @SupportedSourceVersion(SourceVersion.RELEASE_7) //java @SupportedAnnotationTypes({ // 标注注解处理器支持的注解类型     "com.annotation.SingleDelegate",     "com.annotation.MultiDelegate" }) public class AnnotationProcessor extends AbstractProcessor {  public static final String PACKAGE = "com.poet.delegate"; public static final String CLASS_DESC = "From poet compiler";  public Filer filer; //文件相关的辅助类 public Elements elements; //元素相关的辅助类 public Messager messager; //日志相关的辅助类 public Types types;  @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {     filer = processingEnv.getFiler();     elements = processingEnv.getElementUtils();     messager = processingEnv.getMessager();     types = processingEnv.getTypeUtils();      new SingleDelegateProcessor().process(set, roundEnvironment, this);     new MultiDelegateProcessor().process(set, roundEnvironment, this);      return true; } }

2,在继承AbstractProcessor类中的process方法,处理我们自定义的注解,生成代码:

public class SingleDelegateProcessor implements IProcessor {  @Override public void process(Set<? extends TypeElement> set, RoundEnvironment roundEnv,                 AnnotationProcessor abstractProcessor) { // 查询注解是否存在 Set<? extends Element> elementSet =         roundEnv.getElementsAnnotatedWith(SingleDelegate.class); Set<TypeElement> typeElementSet = ElementFilter.typesIn(elementSet); if (typeElementSet == null || typeElementSet.isEmpty()) {     return; }  // 循环处理注解 for (TypeElement typeElement : typeElementSet) {     if (!(typeElement.getKind() == ElementKind.INTERFACE)) { // 只处理接口类型         continue;     }      // 处理 SingleDelegate,只处理 annotation.classNameImpl() 不为空的注解     SingleDelegate annotation = typeElement.getAnnotation(SingleDelegate.class);     if ("".equals(annotation.classNameImpl())) {         continue;     }     Delegate delegate = annotation.delegate();      // 添加构造器     MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder()             .addModifiers(Modifier.PUBLIC);      // 创建类名相关 class builder     TypeSpec.Builder builder =             ProcessUtils.createTypeSpecBuilder(typeElement, annotation.classNameImpl());      // 处理 delegate     builder = ProcessUtils.processDelegate(typeElement, builder,             constructorBuilder, delegate);      // 检查是否继承其它接口     builder = processSuperSingleDelegate(abstractProcessor, builder, constructorBuilder, typeElement);      // 完成构造器     builder.addMethod(constructorBuilder.build());      // 创建 JavaFile     JavaFile javaFile = JavaFile.builder(AnnotationProcessor.PACKAGE, builder.build()).build();     try {         javaFile.writeTo(abstractProcessor.filer);     } catch (IOException e) {         e.printStackTrace();     } } }

3,在项目Gradle中添加 annotationProcessor project 引用

compile project(':apt-delegate-annotation')  annotationProcessor project(':apt-delegate-compiler')

4,如果有自定义注解的话,创建一个java的Module,专门放入自定义注解。项目与apt Module都需引用自定义注解Module

4-1,主工程:

compile project(':apt-delegate-annotation')  annotationProcessor project(':apt-delegate-compiler')

4-2,apt Module:

compile project(':apt-delegate-annotation')  compile 'com.google.auto.service:auto-service:1.0-rc2' compile 'com.squareup:javapoet:1.4.0'

5,生成的源代码在build/generated/source/apt下可以看到

Android APT怎么使用

难点

就apt本身来说没有任何难点可言,难点一在于设计模式和解耦思想的灵活应用,二在与代码生成的繁琐,你可以手动字符串拼接,当然有更高级的玩法用squareup的javapoet,用建造者的模式构建出任何你想要的源代码

优点

它的强大之处无需多言,看代表框架的源码,你可以学到很多新姿势。总的一句话:它可以做任何你不想做的繁杂的工作,它可以帮你写任何你不想重复代码。懒人福利,老司机必备神技,可以提高车速,让你以任何姿势漂移。它可以生成任何源代码供你在任何地方使用,就像剑客的剑,快疾如风,无所不及

我想稍微研究一下,APT还可以在哪些地方使用,比如:Repository层?

APT在Repository层的尝试

了解APT与简单学习之后,搭建Repository层时,发现有一些简单,重复模版的代码

每一次添加新接口都需要简单地修改很多地方,能不能把一部分代码自动生成,减少改动的次数呢?

Repository层

Android APT怎么使用

IRemoteDataSource, RemoteDataSourceImpl

远程数据源,属于网络请求相关

ILocalDataSource, LocalDataSourceImpl

本地数据源,属于本地数据持久化相关

IRepository,RepositoryImpl

仓库代理类,代理远程数据源与本地数据源

Repository层APT设计思路

发现在具体实现类中,大多都是以代理类的形式调用:方法中调用代理对象,方法名称与参数,返回值类型都相同。显然可以进行APT的尝试

  • 简单的情况,具体实现类中只有一个代理对象

  • 复杂的情况,有多个代理对象,方法内并有一些变化

期望结果:

  • 把RemoteDataSourceImpl自动化生成

  • 把LocalDataSourceImpl自动化生成

  • 把RepositoryImpl自动化生成

自定义注解设计

要想具体实现类自动生成,首先要知道需要什么:

  • 方便自动生成java文件的类库

  • 自动生成类名字是什么

  • 需要注入的代理对象

  • 让代理对象代理的方法集

自动生成java文件的类库,可以使用 squareup javapoet

自动生成类名字,代理对象,方法集需要通过自定义注解配置参数的形成,在AbstractProcessor中获取

Delegate

@Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) public @interface Delegate {  /**  * delegate class package  */ String delegatePackage();  /**  * delegate class name  */ String delegateClassName();  /**  * delegate simple name  */ String delegateSimpleName(); }

SingleDelegate

@Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) public @interface SingleDelegate {  /**  * impl class name  */ String classNameImpl();  /**  * delegate data  */ Delegate delegate(); }

MultiDelegate

@Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) public @interface MultiDelegate {  /**  * impl class name  */ String classNameImpl();  /**  * delegate list  */ Delegate[] Delegates(); }

处理自定义的注解、生成代码

AnnotationProcessor

@AutoService(Processor.class) // javax.annotation.processing.IProcessor @SupportedSourceVersion(SourceVersion.RELEASE_7) //java @SupportedAnnotationTypes({ // 标注注解处理器支持的注解类型     "com.annotation.SingleDelegate",     "com.annotation.MultiDelegate" }) public class AnnotationProcessor extends AbstractProcessor {  public static final String PACKAGE = "com.poet.delegate"; public static final String CLASS_DESC = "From poet compiler";  public Filer filer; //文件相关的辅助类 public Elements elements; //元素相关的辅助类 public Messager messager; //日志相关的辅助类 public Types types;  @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {     filer = processingEnv.getFiler();     elements = processingEnv.getElementUtils();     messager = processingEnv.getMessager();     types = processingEnv.getTypeUtils();      new SingleDelegateProcessor().process(set, roundEnvironment, this);     new MultiDelegateProcessor().process(set, roundEnvironment, this);      return true; } }

到此,相信大家对“Android APT怎么使用”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI