安卓AOP三剑客之Android APT技术浅谈

通过学习与使用square公司的开源项目javapoet,来实现仓库层动态生成代码

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

Android APT

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

代表框架:

  • DataBinding
  • Dagger2
  • ButterKnife
  • EventBus3
  • DBFlow
  • AndroidAnnotation

使用姿势

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


  1. @AutoService(Processor.class) // javax.annotation.processing.IProcessor 
  2. @SupportedSourceVersion(SourceVersion.RELEASE_7) //java 
  3. @SupportedAnnotationTypes({ // 标注注解处理器支持的注解类型 
  4.     "com.annotation.SingleDelegate", 
  5.     "com.annotation.MultiDelegate" 
  6. }) 
  7. public class AnnotationProcessor extends AbstractProcessor { 
  8.  
  9. public static final String PACKAGE = "com.poet.delegate"; 
  10. public static final String CLASS_DESC = "From poet compiler"; 
  11.  
  12. public Filer filer; //文件相关的辅助类 
  13. public Elements elements; //元素相关的辅助类 
  14. public Messager messager; //日志相关的辅助类 
  15. public Types types; 
  16.  
  17. @Override 
  18. public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { 
  19.     filer = processingEnv.getFiler(); 
  20.     elements = processingEnv.getElementUtils(); 
  21.     messager = processingEnv.getMessager(); 
  22.     types = processingEnv.getTypeUtils(); 
  23.  
  24.     new SingleDelegateProcessor().process(set, roundEnvironment, this); 
  25.     new MultiDelegateProcessor().process(set, roundEnvironment, this); 
  26.  
  27.     return true; 

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


  1. public class SingleDelegateProcessor implements IProcessor {  
  2. @Override 
  3. public void process(Set<? extends TypeElement> set, RoundEnvironment roundEnv, 
  4.                 AnnotationProcessor abstractProcessor) { 
  5. // 查询注解是否存在 
  6. Set<? extends Element> elementSet = 
  7.         roundEnv.getElementsAnnotatedWith(SingleDelegate.class); 
  8. Set<TypeElement> typeElementSet = ElementFilter.typesIn(elementSet); 
  9. if (typeElementSet == null || typeElementSet.isEmpty()) { 
  10.     return; 
  11. }  
  12. // 循环处理注解 
  13. for (TypeElement typeElement : typeElementSet) { 
  14.     if (!(typeElement.getKind() == ElementKind.INTERFACE)) { // 只处理接口类型 
  15.         continue; 
  16.     } 
  17.  
  18.     // 处理 SingleDelegate,只处理 annotation.classNameImpl() 不为空的注解 
  19.     SingleDelegate annotation = typeElement.getAnnotation(SingleDelegate.class); 
  20.     if ("".equals(annotation.classNameImpl())) { 
  21.         continue; 
  22.     } 
  23.     Delegate delegate = annotation.delegate(); 
  24.  
  25.     // 添加构造器 
  26.     MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder() 
  27.             .addModifiers(Modifier.PUBLIC); 
  28.  
  29.     // 创建类名相关 class builder 
  30.     TypeSpec.Builder builder = 
  31.             ProcessUtils.createTypeSpecBuilder(typeElement, annotation.classNameImpl()); 
  32.  
  33.     // 处理 delegate 
  34.     builder = ProcessUtils.processDelegate(typeElement, builder, 
  35.             constructorBuilder, delegate); 
  36.  
  37.     // 检查是否继承其它接口 
  38.     builder = processSuperSingleDelegate(abstractProcessor, builder, constructorBuilder, typeElement); 
  39.  
  40.     // 完成构造器 
  41.     builder.addMethod(constructorBuilder.build()); 
  42.  
  43.     // 创建 JavaFile 
  44.     JavaFile javaFile = JavaFile.builder(AnnotationProcessor.PACKAGE, builder.build()).build(); 
  45.     try { 
  46.         javaFile.writeTo(abstractProcessor.filer); 
  47.     } catch (IOException e) { 
  48.         e.printStackTrace(); 
  49.     } 

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


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

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

4-1,主工程:


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

4-2,apt Module:


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

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

难点

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

优点

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

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

APT在Repository层的尝试

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

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

Repository层

IRemoteDataSource, RemoteDataSourceImpl

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

ILocalDataSource, LocalDataSourceImpl

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

IRepository,RepositoryImpl

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

Repository层APT设计思路

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

  • 简单的情况,具体实现类中只有一个代理对象
  • 复杂的情况,有多个代理对象,方法内并有一些变化

期望结果:

  • 把RemoteDataSourceImpl自动化生成
  • 把LocalDataSourceImpl自动化生成
  • 把RepositoryImpl自动化生成

自定义注解设计

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

  • 方便自动生成java文件的类库
  • 自动生成类名字是什么
  • 需要注入的代理对象
  • 让代理对象代理的方法集

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

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

Delegate


  1. @Retention(RetentionPolicy.SOURCE) 
  2. @Target(ElementType.TYPE) 
  3. public @interface Delegate { 
  4.  
  5. /** 
  6.  * delegate class package 
  7.  */ 
  8. String delegatePackage(); 
  9.  
  10. /** 
  11.  * delegate class name 
  12.  */ 
  13. String delegateClassName(); 
  14.  
  15. /** 
  16.  * delegate simple name 
  17.  */ 
  18. String delegateSimpleName(); 

SingleDelegate


  1. @Retention(RetentionPolicy.SOURCE) 
  2. @Target(ElementType.TYPE) 
  3. public @interface SingleDelegate { 
  4.  
  5. /** 
  6.  * impl class name 
  7.  */ 
  8. String classNameImpl(); 
  9.  
  10. /** 
  11.  * delegate data 
  12.  */ 
  13. Delegate delegate(); 

MultiDelegate


  1. @Retention(RetentionPolicy.SOURCE) 
  2. @Target(ElementType.TYPE) 
  3. public @interface MultiDelegate {  
  4. /** 
  5.  * impl class name 
  6.  */ 
  7. String classNameImpl();  
  8. /** 
  9.  * delegate list 
  10.  */ 
  11. Delegate[] Delegates(); 

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

AnnotationProcessor


  1. @AutoService(Processor.class) // javax.annotation.processing.IProcessor 
  2. @SupportedSourceVersion(SourceVersion.RELEASE_7) //java 
  3. @SupportedAnnotationTypes({ // 标注注解处理器支持的注解类型 
  4.     "com.annotation.SingleDelegate", 
  5.     "com.annotation.MultiDelegate" 
  6. }) 
  7. public class AnnotationProcessor extends AbstractProcessor {  
  8. public static final String PACKAGE = "com.poet.delegate"; 
  9. public static final String CLASS_DESC = "From poet compiler";  
  10. public Filer filer; //文件相关的辅助类 
  11. public Elements elements; //元素相关的辅助类 
  12. public Messager messager; //日志相关的辅助类 
  13. public Types types;  
  14. @Override 
  15. public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { 
  16.     filer = processingEnv.getFiler(); 
  17.     elements = processingEnv.getElementUtils(); 
  18.     messager = processingEnv.getMessager(); 
  19.     types = processingEnv.getTypeUtils(); 
  20.  
  21.     new SingleDelegateProcessor().process(set, roundEnvironment, this); 
  22.     new MultiDelegateProcessor().process(set, roundEnvironment, this); 
  23.  
  24.     return true; 

原文发布时间为:2017-10-16
本文作者:佚名
本文来自合作伙伴“51CTO”,了解相关信息可以关注。

时间: 2025-01-26 08:51:09

安卓AOP三剑客之Android APT技术浅谈的相关文章

偷也是门技术——浅谈XMLHTTP应用:新闻小偷[转]

xml 本文参考互联网整理而成(在此感谢资料奉献者).希望本文尽量系统,尽量易懂. 偷,即无劳而获.在网络上,诸如某大型权威站点发布了新闻,而自己的小小站点也想与时俱进,和人家一样同步更新,多N啊.于是,偷就是最好的办法了.偷是不道德的,不鼓励偷,但又不提倡不偷,都是技术惹的祸,扯远了~! 小偷程序是什么? 其实是通过XML中的XMLHTTP对象调用其它网站上的网页,甚至可以将接受的HTML代码进行过滤以获得需要内容(比如提取某某气象站,不可能是将整站提取显示,而只是需要显示天气的那部分). 其

民用报警服务技术浅谈

报警行业的设备和系统数字化.网络化的速度在加快,未来的报警服务行业市场是网络化的专属,传统的报警服务商业模式正在发生变化,通过卖产品和施工实现盈利的方式在弱化.在互联网时代,报警服务企业在实现技术变现的时候,更多要依靠服务去获得市场和用户的认可. 相对于传统的报警设备,网络化的报警设备在布线和安装上都有了长足的进步,加上IPC的软硬件,以及移动端的开发应用,如今的报警操作系统不仅使用方便,提高用户的使用体验,还改变了传统报警的样式,使得接警人员对报警区域进行可视化联动操作,降低误报率和报警运营中

Android开发:浅谈MVP模式应用与内存泄漏问题解决

最近博主开始在项目中实践MVP模式,却意外发现内存泄漏比较严重,但却很少人谈到这个问题,促使了本文的发布,本文假设读者已了解MVP架构. MVP简介 M-Modle,数据,逻辑操作层,数据获取,数据持久化保存.比如网络操作,数据库操作 V-View,界面展示层,Android中的具体体现为Activity,Fragment P-Presenter,中介者,连接Modle,View层,同时持有modle引用和view接口引用 示例代码 Modle层操作 public class TestModle

Android 利用 APT 技术在编译期生成代码_Android

APT(Annotation Processing Tool 的简称),可以在代码编译期解析注解,并且生成新的 Java 文件,减少手动的代码输入.现在有很多主流库都用上了 APT,比如 Dagger2, ButterKnife, EventBus3 等,我们要紧跟潮流,与时俱进呐! (ง •̀_•́)ง 下面通过一个简单的 View 注入项目 ViewFinder 来介绍 APT 相关内容,简单实现了类似于ButterKnife 中的两种注解 @BindView 和 @OnClick . 项目

[Android 泥水匠] Android基础 之一:浅谈Android架构到HelloWorld案例的剖析

1.1前言   泥瓦匠又和大家见面了,在移动平台干过原生态开发,也干过hybrid应用.可以看看相关的文章 Android UI .所以多多少少在这块还是有点了解.现在很多高级语言可以开发app程序,包括Android,到我觉得目前Java语言开发Android程序还是很火,很重要的.自然,Java的底子不可少.可以看看泥瓦匠写的不少基础 Java Basic .   我们生活在一个通讯的时代,我经历过得2.5G时代,也就是GPRS等的时代,前面还有2G(GSM等).1G,后面则大家熟悉的3G

Android开发技术周报 Issue#17

Android开发技术周报 Issue#17 声明:所有内容收集整理自网络.如有侵权,请联系删除.微信公众号上请点击"阅读原文"阅读完整版本. 业界新闻 1. Google 正秘密开发第三款操作系统 Fuchsia 这是一款开源的.实时操作系统,被其称作Fuchsia.与Android和Chrome OS不同,Fuchsia不是基于Linux,它使用一个全新的.由谷歌开发的微内核,称作"Magenta". 2. 媲美 Google,腾讯推出自研图片编码格式 TPG

Android开发技术周报 Issue#4

作者:snowdreamEmail:yanghui1986527#gmail.comGithub: https://github.com/snowdreamQQ 群: 529327615原文地址:http://t.cn/RMFx55Q Android开发技术周报 Issue#4 声明:所有内容收集整理自网络.如有侵权,请联系删除. 业界新闻 1. 谷歌I/O 2017大会日期地址公布:5月17日举办 根据官方推特分析,Google I/O 2017开发者大会将于5月17日至19日,于加州山景城的

Android开发技术周报 Issue#12

Android开发技术周报 Issue#12 声明:所有内容收集整理自网络.如有侵权,请联系删除.微信公众号上请点击"阅读原文"阅读完整版本. 业界新闻 1. Android Studio 2.4 Preview 4 发布,内置 Java 8 支持 Android Studio 2.4 Preview 4 发布了.Android Studio 2.4 的最新预览版包括构建工具和模拟器中的 Google Play 的更新,以及一些错误修复. 2. Android 超越 Windows 成

Android应用安全开发之浅谈密钥硬编码

Android应用安全开发之浅谈密钥硬编码 作者:伊樵.呆狐@阿里聚安全 1 简介 在阿里聚安全的漏洞扫描器中和人工APP安全审计中,经常发现有开发者将密钥硬编码在Java代码.文件中,这样做会引起很大风险.信息安全的基础在于密码学,而常用的密码学算法都是公开的,加密内容的保密依靠的是密钥的保密,密钥如果泄露,对于对称密码算法,根据用到的密钥算法和加密后的密文,很容易得到加密前的明文:对于非对称密码算法或者签名算法,根据密钥和要加密的明文,很容易获得计算出签名值,从而伪造签名. 2 风险案例 密