关于Apt注解实践与总结【包含20篇博客】
YCApt关于apt方案实践与总结
目录介绍
- 00.注解系列博客汇总
- 01.什么是apt
- 02.annotationProcessor和apt区别
- 03.项目目录结构
- 04.该案例作用
- 05.使用说明
- 06.编译期注解生成代码[点击事件案例]
- 07.运行期注解案例[setContentView案例]
- 08.使用注解替代枚举
09.使用注解搭建路由[综合案例]
- 9.1 搭建路由条件
- 9.2 通过注解去实现路由跳转
- 9.3 自定义路由Processor编译器
- 9.4 利用apt生成路由映射文件
- 9.5 路由框架的设计
- 9.6 路由参数的传递和接收
- 9.7 为何需要依赖注入
- 9.8 Activity属性注入
- 9.9 路由开源库的使用
关于apt实践与总结开源库地址
https://github.com/yangchong2...
00.注解系列博客汇总
0.1 注解基础系列博客
01.Annotation注解详细介绍
1.Annotation库的简单介绍 2.@Nullable和@NonNull 3.资源类型注释 4.类型定义注释 5.线程注释 6.RGB颜色纸注释 7.值范围注释 8.权限注释 9.重写函数注释 10.返回值注释 11.@Keep注释 12.@SuppressWarnings注解 13.其他
- [02.Dagger2深入分析,待更新]()
03.注解详细介绍
- 什么是注解,注解分类有哪些?自定义注解分类?运行注解案例展示分析,以一个最简单的案例理解注解……使用注解替代枚举,使用注解限定类型
04.APT技术详解
- 什么是apt?理解注解处理器的作用和用途……android-apt被替代?annotationProcessor和apt区别? 什么是jack编译方式?
06.自定义annotation注解
- @Retention的作用?@Target(ElementType.TYPE)的解释,@Inherited注解可以被继承吗?Annotation里面的方法为何不能是private?
07.注解之兼容kotlin
- 后期更新
08.注解之处理器类Processor
- 处理器类Processor介绍,重要方法,Element的作用,修饰方法的注解和ExecutableElement,了解修饰属性、类成员的注解和VariableElement……
10.注解遇到问题和解决方案
- 无法引入javax包下的类库,成功运行一次,修改代码后再运行就报错
11.注解代替枚举
- 在做内存优化时,推荐使用注解代替枚举,因为枚举占用的内存更高,如何说明枚举占用内存高呢?这是为什么呢?
12.注解练习案例开源代码
- 注解学习小案例,比较系统性学习注解并且应用实践。简单应用了运行期注解,通过注解实现了setContentView功能;简单应用了编译器注解,通过注解实现了防暴力点击的功能,同时支持设置时间间隔;使用注解替代枚举;使用注解一步步搭建简单路由案例。结合相应的博客,在来一些小案例,从此应该对注解有更加深入的理解……
0.2 注解系列博客问题答疑
- 13.0.0.1 什么是注解?系统内置的标准注解有哪些?SuppressWarnings用过没?Android中提供了哪些与线程相关的注解?
- 13.0.0.2 什么是apt?apt的难点和优势?什么是注解处理器?抽象处理器中四个方法有何作用?annotationProcessor和apt区别?
- 13.0.0.3 注解是怎么分类的?自定义注解又是怎么分类的?运行期注解原理是什么?实际注解案例有哪些?
- 13.0.0.4 在自定义注解中,Annotation里面的方法为何不能是private?Annotation里面的方法参数有哪些?
- 13.0.0.5 @Inherited是什么意思?注解是不可以继承的,这是为什么?注解的继承这个概念该如何理解?
- 13.0.0.6 什么是依赖注入?依赖注入案例举例说明,有哪些方式,具备什么优势?依赖查找和依赖注入有什么区别?
- 13.0.0.7 路由框架为何需要依赖注入,不用的话行不行?路由用什么方式注入,这些注入方式各具何特点,为何选择注解注入?
- 13.0.0.8 实际开发中使用到注解有哪些,使用注解替代枚举?如何通过注解限定传入的类型?为何说枚举损耗性能?
01.什么是apt
什么是apt
- APT,就是Annotation Processing Tool的简称,就是可以在代码编译期间对注解进行处理,并且生成Java文件,减少手动的代码输入。注解我们平时用到的比较多的可能会是运行时注解,比如大名鼎鼎的retrofit就是用运行时注解,通过动态代理来生成网络请求。编译时注解平时开发中可能会涉及的比较少,但并不是说不常用,比如我们经常用的轮子Dagger2, ButterKnife, EventBus3 都在用,所以要紧跟潮流来看看APT技术的来龙去脉。
编译时注解。
- 也有人叫它代码生成,其实他们还是有些区别的,在编译时对注解做处理,通过注解,获取必要信息,在项目中生成代码,运行时调用,和直接运行手写代码没有任何区别。而更准确的叫法:APT - Annotation Processing Tool
大概原理
- Java API 已经提供了扫描源码并解析注解的框架,开发者可以通过继承 AbstractProcessor 类来实现自己的注解解析逻辑。APT 的原理就是在注解了某些代码元素(如字段、函数、类等)后,在编译时编译器会检查 AbstractProcessor 的子类,并且自动调用其 process() 方法,然后将添加了指定注解的所有代码元素作为参数传递给该方法,开发者再根据注解元素在编译期输出对应的 Java 代码
02.annotationProcessor和apt区别
annotationProcessor和apt区别
- Android 官方的 annotationProcessor 同时支持 javac 和 jack 编译方式,而 android-apt 只支持 javac 方式。当然,目前 android-apt 在 Android Gradle 插件 2.2 版本上面仍然可以正常运行,如果你没有想支持 jack 编译方式的话,可以继续使用 android-apt。
- 目前比如一些常用框架dagger2,butterKnife,ARouter等,都支持annotationProcessor
什么是jack编译方式?
- Jack (Java Android Compiler Kit)是新的Android 编译工具,从Android 6.0 开始加入,替换原有的编译工具,例如javac, ProGuard, jarjar和 dx。它主要负责将java代码编译成dex包,并支持代码压缩,混淆等。
Jack工具的主要优势
- 完全开放源码,源码均在AOSP中,合作伙伴可贡献源码
- 加快编译源码,Jack 提供特殊的配置,减少编译时间:pre-dexing, 增量编译和Jack编译服务器.
- 支持代码压缩,混淆,重打包和multidex,不在使用额外单独的包,例如ProGuard。
03.项目目录结构
项目目录结构如图:
- app:Demo
- AptAnnotation:java Library主要放一些项目中需要用到的自定义注解及相关代码
- AptApi:Android Library. 是我们真正对外发布并交由第三方使用的库,它引用了apt-jar包
- AptCompiler:java Library主要是应用apt技术处理注解,生成相关代码或者相关源文件,是核心所在。
04.该案例作用
- 前期仅仅是为了学习,同时先让demo运行起来,虽然网上很多讲解apt的博客写的很详细,但是还是有必要结合实际案例练习一下。
使用apt实现点击事件【编译期注解生成代码】
- 在一定时间内,按钮点击事件只能执行一次。未到指定时间,不执行点击事件。
使用apt实现setContentView功能【运行期注解案例】
- 使用简单的注解,便可以设置布局,等效于setContentView(R.layout.activity_main)
使用apt实现路由【综合型案例】
- 比较全面的介绍从零起步,一步一步封装简易的路由开源库。一共用10篇博客记录了大部分的过程,想要更加深入了解,欢迎clone该项目。
05.使用说明
如下所示
@Override protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//初始化OnceClick,并设置点击事件间隔是2秒OnceInit.once(this,2000); }@OnceClick(R.id.tv_1) public void Click1(){Log.d("tag--------------------","tv_1"); }
06.编译期注解生成代码
如下所示,在app/build/generated/source/apt/debug/MainActivity$$_Once_Proxy目录下
// 编译生成的代码,不要修改 // 更多内容:https://github.com/yangchong211 package com.ycbjie.ycapt;import android.view.View; import com.ycbjie.api.Finder; import com.ycbjie.api.AbstractInjector;public class MainActivity$$_Once_Proxy<T extends MainActivity> implements AbstractInjector<T> {public long intervalTime;@Overridepublic void setIntervalTime(long time) {intervalTime = time;}@Overridepublic void inject(final Finder finder, final T target, Object source) {View view;view = finder.findViewById(source, 2131165325);if(view != null){view.setOnClickListener(new View.OnClickListener() {long time = 0L;@Overridepublic void onClick(View v) {long temp = System.currentTimeMillis();if (temp - time >= intervalTime) {time = temp;target.Click1();}}});}view = finder.findViewById(source, 2131165326);if(view != null){view.setOnClickListener(new View.OnClickListener() {long time = 0L;@Overridepublic void onClick(View v) {long temp = System.currentTimeMillis();if (temp - time >= intervalTime) {time = temp;target.Click2(v);}}});}}}
07.运行期注解案例
首先先定义自定义注解
//@Retention用来修饰这是一个什么类型的注解。这里表示该注解是一个运行时注解。 @Retention(RetentionPolicy.RUNTIME) //@Target用来表示这个注解可以使用在哪些地方。比如:类、方法、属性、接口等等。 //这里ElementType.TYPE 表示这个注解可以用来修饰:Class, interface or enum declaration。 //当你用ContentView修饰一个方法时,编译器会提示错误。 @Target({ElementType.TYPE}) //这里的interface并不是说ContentView是一个接口。 //就像申明类用关键字class。申明枚举用enum。申明注解用的就是@interface。 public @interface ContentView {//返回值表示这个注解里可以存放什么类型值。int value(); }
然后需要在activity中做注解解析
@SuppressLint("Registered") public class ContentActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//注解解析//遍历所有的子类for (Class c = this.getClass(); c != Context.class; c = c.getSuperclass()) {assert c != null;//找到修饰了注解ContentView的类ContentView annotation = (ContentView) c.getAnnotation(ContentView.class);if (annotation != null) {try {//获取ContentView的属性值int value = annotation.value();//调用setContentView方法设置viewthis.setContentView(value);} catch (RuntimeException e) {e.printStackTrace();}return;}}} }
关于如何使用,注意你写的Activity需要实现ContentActivity,才能让注解生效
@ContentView(R.layout.activity_four) public class FourActivity extends ContentActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);findViewById(R.id.tv_1).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(FourActivity.this,"运行期注解",Toast.LENGTH_SHORT).show();}});} }
09.使用注解搭建路由[综合案例]
9.1 ARouter路由解析
- 比较详细地分析了阿里路由库
9.1 搭建路由条件
- 为何需要路由?实现路由方式有哪些,这些方式各有何优缺点?使用注解实现路由需要具备的条件以及简单原理分析……
9.2 通过注解去实现路由跳转
- 自定义Router注解,Router注解里有path和group,这便是仿照ARouter对路由进行分组。然后看看注解生成的代码,手写路由跳转代码。
9.3 自定义路由Processor编译器
- Processor介绍,重要方法,Element的作用,修饰方法的注解和ExecutableElement
9.4 利用apt生成路由映射文件
- 在Activity类上加上@Router注解之后,便可通过apt来生成对应的路由表,那么究竟是如何生成的代码呢?
- 在组件化开发中,有多个module,为何要在build.gradle配置moduleName,又是如何通过代码拿到module名称?
- process处理方法如何生成代码的,又是如何写入具体的路径,写入文件的?
- 看完这篇文章,应该就能够理解上面这些问题呢!
9.5 路由框架的设计和初始化
- 编译期是在你的项目编译的时候,这个时候还没有开始打包,也就是你没有生成apk呢!路由框架在这个时期根据注解去扫描所有文件,然后生成路由映射文件。这些文件都会统一打包到apk里,app运行时期做的东西也不少,但总而言之都是对映射信息的处理,如执行执行路由跳转等。那么如何设计框架呢?
- 生成的注解代码,又是如何把这些路由映射关系拿到手,或者说在什么时候拿到手比较合适?为何注解需要进行初始化操作?
- 如何得到得到路由表的类名,如何得到所有的routerAddress---activityClass映射关系?
[9.6 路由框架设计注意要点]()
- 需要注意哪些要点?
9.7 为何需要依赖注入
- 有哪些注入的方式可以解耦,你能想到多少?路由框架为何需要依赖注入?路由为何用注解进行依赖注入,而不是用反射方式注入,或者通过构造方法注入,或者通过接口方式注入?
9.8 Activity属性注入
- 在跳转页面时,如何传递intent参数,或者如何实现跳转回调处理逻辑?
9.9 路由开源库的使用
不带参数直接跳转
@Router(path = Path.six) public class SixActivity extends AppCompatActivity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_six);}}ARouter.getsInstance().build(Path.six).navigation(MainActivity.this, new NavigationCallback() {@Overridepublic void onFound(Postcard postcard) {Log.e("NavigationCallback","找到跳转页面");}@Overridepublic void onLost(Postcard postcard) {Log.e("NavigationCallback","未找到");}@Overridepublic void onArrival(Postcard postcard) {Log.e("NavigationCallback","成功跳转");}});
带参数跳转
@Router(path = Path.five) public class FiveActivity extends AppCompatActivity {@ExtraString title;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_five);//添加这行代码,实际上就是自动生成了下面获取参数值的代码ARouter.getsInstance().inject(this);//如果不添加插入注解,则可以直接用下面的代码。//Intent intent = getIntent();//String title = intent.getStringExtra("title");Toast.makeText(this, "title=" + title, Toast.LENGTH_SHORT).show();}}Bundle bundle = new Bundle(); bundle.putString("title","标题-------------"); ARouter.getsInstance().build(Path.five).withBundle(bundle).navigation();
路由注解生成的代码位置
10.其他说明
00.参考案例
- https://www.jianshu.com/p/335...
- https://www.jianshu.com/p/200...
- https://github.com/joyrun/Act...
- https://github.com/BaronZ88/R...
- https://github.com/alibaba/AR...
- https://github.com/Xiasm/Easy...
- https://github.com/chenenyu/R...
- https://www.jianshu.com/p/8a3...
- https://www.jianshu.com/p/e2d...
01.关于博客汇总链接
- 1.技术博客汇总
- 2.开源项目汇总
- 3.生活博客汇总
- 4.喜马拉雅音频汇总
- 5.其他汇总
02.关于我的博客
- 我的个人站点:www.yczbj.org,www.ycbjie.cn
- github:https://github.com/yangchong211
- 知乎:https://www.zhihu.com/people/...
- 简书:http://www.jianshu.com/u/b7b2...
- csdn:http://my.csdn.net/m0_37700275
- 喜马拉雅听书:http://www.ximalaya.com/zhubo...
- 开源中国:https://my.oschina.net/zbj161...
- 泡在网上的日子:http://www.jcodecraeer.com/me...
- 邮箱:yangchong211@163.com
- 阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV
- segmentfault头条:https://segmentfault.com/u/xi...
- 掘金:https://juejin.im/user/593943...
关于apt实践与总结开源库地址
https://github.com/yangchong2...
关于Apt注解实践与总结【包含20篇博客】相关推荐
- 自定义依赖注解无效_关于Apt注解实践与总结【包含20篇博客】
超详细!安卓巴士开发者大会嘉宾及主题介绍 目录介绍 00.注解系列博客汇总 01.什么是apt 02.annotationProcessor和apt区别 03.项目目录结构 04.该案例作用 05.使 ...
- Python爬虫小实践:爬取任意CSDN博客所有文章的文字内容(或可改写为保存其他的元素),间接增加博客访问量...
Python并不是我的主业,当初学Python主要是为了学爬虫,以为自己觉得能够从网上爬东西是一件非常神奇又是一件非常有用的事情,因为我们可以获取一些方面的数据或者其他的东西,反正各有用处. 这两天闲 ...
- 20个博客SEO优化技巧
转自:http://lusongsong.com/reed/114.html SEO优化也就是搜索引擎优化,搜索引擎优化也就是博客内容被搜索引擎收录及优先排序,以此增加博客的点击率和曝光度,最终提升博 ...
- 美团配送数据治理实践【转载美团技术团队博客】
大数据时代的到来,让越来越多的企业看到了数据资产的价值.将数据视为企业的重要资产,已经成为业界的一种共识,企业也在快速探索应用场景和商业模式,并开始建设技术平台. 但这里要特别强调一下,如果在大数据& ...
- 软件工程综合实践专题第三次个人博客作业
一.简介 Mockplus(摹客)是一款简洁快速的原型图设计工具.适合软件团队.个人在软件开发的设计阶段使用.其低保真.无需学习.快速上手.功能够用.并能够很好地表达自己的设计 二.安装 先在官网下载 ...
- 面试官问:你做过什么Java线程池实践,我写了一篇博客给他看~
线程池大家都## 标题很熟悉,无论是平时的业务开发还是框架中间件都会用到,大部分都是基于JDK线程池ThreadPoolExecutor做的封装, 都会牵涉到这几个核心参数的设置:核心线程数,等待(任 ...
- Docker 实践 - 使用docker搭建一个个人博客
前言 搭建这个博客系统使用的 D 大佬的 solo 开源地址 https://gitee.com/dl88250/solo 他的哔哩哔哩 https://space.bilibili.com/5267 ...
- AndroidStudio3.4.2 gradle5.1.1 apt注解解释器不执行
最近在学习注解是遇到一个坑,就是android studio升级到3.4.2,gradle升级到5.1.1后,apt不会执行,没办法自动生成注解文件. 搞了一个下午,终于找到一篇博客,解决了这个问题. ...
- Python自动生成10000个java类使用APT注解后引发的问题
前言 前面写了一篇关于自己开发的一个基于APT注解的用于RecyclerView复杂楼层的开源框架,框架的原理比较简单,通过注解,在编译期会生成一个ComponentRule.java的文件,然后建立 ...
最新文章
- mysql 配置文件绑定ip_(三)设置mysql允许外部IP连接的解决方法及遇到的坑说明...
- sqlmap 获取mysql密码_利用sqlmap 获取管理员账号密码
- boost::mp11::mp_replace_at_c相关用法的测试程序
- Unicode与JavaScript详解 [很好的文章转]
- Idea中Spring整合MyBatis框架中配置文件中对象注入问题解决方案
- 使用axure的团队项目功能
- 暑假集训第四场选拔赛 解题报告
- Dev-C++配置问题
- SAPI V1.4发布,轻巧的API输出测试组件
- maven安装Ojdbc6
- Java读取ID卡卡号源码
- 北京市居民公共交通出行特征
- armbian 下载加速
- chrome使用tab键切换搜索
- 物权法全文内容有哪些呢-广告外链_有哪些网络推广免费平台?通过哪些平台进行免费推广及注意事项?...
- gsoc 任务_gsoc20第3集从谱线中识别元素
- async 函数的含义和用法
- 列表推导式-list comprehension
- 参考文献中各字母的含义
- linux 重启kettle服务_Linux下面kettle的部署
热门文章
- Win10安装Ubuntu18.04双系统,图文详解,全网最详细教程
- 使用cmd命令 ping网段内的使用的IP并输出到文件
- 外部接口需求怎么写_怎么写财务工作报告?送你16套高逼格财务工作报告范文PPT模板,满足不同行业会计需求!...
- linux执行定时,linux定时执行 - 乄珍惜
- linux ping不允许的操作,Alpine ping:不允许操作
- 在PHP中2中特殊数据类型是,@PHP中的数据类型(2)
- android多版本打包,Android的持续化集成及多版本打包
- 空间留言工具_新房,拖把等清洁工具都放哪?
- DPad down是哪个键_投影仪前3甲PK:双十一坚果J7S和当贝D3X投影仪选择哪个
- linux fread 头文件,Linux文件操作