Android开发学习之路--APT技术
2017-12-13 21:33
645 查看
今年都快要过去了,也已经2个月没有写博客了,主要还是换了新工作,今年都好几家徘徊了,从最初的公司散伙,也快1年了,这么背的17年终于快要结束了。不过庆幸的是加入了目前的公司,一个暂时觉得可以锻炼自己的平台。从嵌入式到app到嵌入式android系统,这次又回到了app,希望这次可以深耕3-5年,能在移动互联网站稳脚跟。两个月的时间忙于熟悉了解公司业务,也少了自己学习的时间,机器学习还没继续,android也没有深入了解,是时候补一把了。
以前遇到Dagger2, ButterKnife, EventBus3等的都是直接用,也没有太关心内部的源码实现。当想看的时候,发现一堆的注解不是非常好理解,所以还是先打打基础学习下apt技术吧,虽然不是那么新鲜了。
然后实际的生成的代码如下:
Android开发学习之路–Annotation注解简化view控件之初体验
一年前刚接触的时候写的,勉强还能理解哈,这里主要还是实现了运行时的注解,用了反射肯定是需要消耗一定的性能。上述的butterknife生成的代码可是编译时生成的代码,基本不消耗性能的。
APT(Annotation Processing Tool)是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,使用Annotation进行额外的处理。 Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定),APT还会将编译生成的源文件和原来的源文件一起生成class文件。
annotationProcessor:APT工具中的一种,他是google开发的内置框架,不需要引入,具体可以直接在build.gradle中使用,比如butterknife和dagger2引入如下:
2.定义注解处理器
3.在处理器里面完成处理方式,通常是生成java代码。
4.注册处理器
5.利用APT完成如下图的工作内容。
BindView注解:
Onclick注解:
主要继承AbstractProcessor实现process方法生成对应的代码,至于AbstractProcessor何时被调用,怎么执行的,还没有做过多深入理解。利用了AutoService:
https://github.com/google/auto/tree/master/service。看一段官方的话:
AutoService will generate the file
META-INF/services/javax.annotation.processing.Processor in the output
classes folder.
在process方法里扫描所有的BindView和OnClick注解,然后javapoet来生成代码,这里生成代码的class为MAinActivity$$Finder.class,具体的实现可以参考github的例子,已经注释得很清楚了(例子源码在文末的链接中)。
若想要更深入理解javapoet的使用,可以参考这里:javapoet
很明显这里就是我们平时写的findview啊,setOnclickLIstener等方法的具体实现。通过注解,然后自动生成代码,注入到我们需要的类中。就免去了很多的重复劳动力,而且不会影响代码的运行效率。
实现ViewFinder的static的inject方法,用于注入代码。最后调用到注解处理器中生成的xxx$$Finder类的inject方法。其中这里xxx既是MainActivity。
编译期间
processor模块里的自定义的MyProcessor类的process会扫描所有的注解,然后生成自定义的XXX$$Finder.class代码。
使用期间
首先使用注解@BindView(R.id.tv_info)以及@OnClick({R.id.bt_change, R.id.bt_reset}),
接着MainActivity的onCreate方法中调用
ViewFinder.inject(this);方法来注入编译期间生成的代码。
关于apt技术基本上也了解了,说了那么多其实把例子敲一遍就都明白了。
github源码例子点击这里
参考:
http://blog.chengyunfeng.com/?p=1021
http://blog.csdn.net/u011315960/article/details/64441120
http://blog.csdn.net/hj7jay/article/details/52180023
https://github.com/sockeqwe/annotationprocessing101
以前遇到Dagger2, ButterKnife, EventBus3等的都是直接用,也没有太关心内部的源码实现。当想看的时候,发现一堆的注解不是非常好理解,所以还是先打打基础学习下apt技术吧,虽然不是那么新鲜了。
1.前言
首先看下butterknife生成的代码,要是都自己来敲,那就没法去和女神约会潇洒了。作为有家室的,也得多留点时间陪媳妇。@BindView(R.id.iv_left_menu) ImageView ivLeftMenu; @BindView(R.id.iv_add) ImageView ivAdd; @BindView(R.id.toolbar) Toolbar toolbar; @BindView(R.id.rv_content) RecyclerView rvRobots; @BindView(R.id.coordinator_layout) LinearLayout coordinatorLayout;
然后实际的生成的代码如下:
public class Main2Fragment_ViewBinding implements Unbinder { private Main2Fragment target; @UiThread public Main2Fragment_ViewBinding(Main2Fragment target, View source) { this.target = target; target.ivLeftMenu = Utils.findRequiredViewAsType(source, R.id.iv_left_menu, "field 'ivLeftMenu'", ImageView.class); target.ivAdd = Utils.findRequiredViewAsType(source, R.id.iv_add, "field 'ivAdd'", ImageView.class); target.toolbar = Utils.findRequiredViewAsType(source, R.id.toolbar, "field 'toolbar'", Toolbar.class); target.rvRobots = Utils.findRequiredViewAsType(source, R.id.rv_content, "field 'rvRobots'", RecyclerView.class); target.coordinatorLayout = Utils.findRequiredViewAsType(source, R.id.coordinator_layout, "field 'coordinatorLayout'", LinearLayout.class); } @Override @CallSuper public void unbind() { Main2Fragment target = this.target; if (target == null) throw new IllegalStateException("Bindings already cleared."); this.target = null; target.ivLeftMenu = null; target.ivAdd = null; target.toolbar = null; target.rvRobots = null; target.coordinatorLayout = null; } }
2.注解
那么他是怎么实现的?在此之前需要了解下注解,可以参考下之前的一篇博客:Android开发学习之路–Annotation注解简化view控件之初体验
一年前刚接触的时候写的,勉强还能理解哈,这里主要还是实现了运行时的注解,用了反射肯定是需要消耗一定的性能。上述的butterknife生成的代码可是编译时生成的代码,基本不消耗性能的。
3.什么是APT
理解了注解后,我们开始学习apt吧。APT(Annotation Processing Tool)是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,使用Annotation进行额外的处理。 Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定),APT还会将编译生成的源文件和原来的源文件一起生成class文件。
annotationProcessor:APT工具中的一种,他是google开发的内置框架,不需要引入,具体可以直接在build.gradle中使用,比如butterknife和dagger2引入如下:
dependencies { compile 'com.jakewharton:butterknife:8.8.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' compile 'com.google.dagger:dagger:2.12' annotationProcessor 'com.google.dagger:dagger-compiler:2.12' }
4.APT注解的流程
1.定义注解(如@automain)2.定义注解处理器
3.在处理器里面完成处理方式,通常是生成java代码。
4.注册处理器
5.利用APT完成如下图的工作内容。
5 APT的简单实现
既然了解了apt的过程,那么就来实现下了。5.1 定义注解
新建一个java库,命名为annotation。BindView注解:
@Retention(RetentionPolicy.CLASS) @Target(ElementType.FIELD) public @interface BindView { int value(); }
Onclick注解:
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) public @interface OnClick { int[] value(); }
5.2 定义注解处理器
新建一个java库,命名为processor。主要继承AbstractProcessor实现process方法生成对应的代码,至于AbstractProcessor何时被调用,怎么执行的,还没有做过多深入理解。利用了AutoService:
https://github.com/google/auto/tree/master/service。看一段官方的话:
AutoService will generate the file
META-INF/services/javax.annotation.processing.Processor in the output
classes folder.
在process方法里扫描所有的BindView和OnClick注解,然后javapoet来生成代码,这里生成代码的class为MAinActivity$$Finder.class,具体的实现可以参考github的例子,已经注释得很清楚了(例子源码在文末的链接中)。
若想要更深入理解javapoet的使用,可以参考这里:javapoet
5.3 编译生成代码
编译后在app/build/generated/source/apt/debug/com/jared/helloapt目录下会生成对应的MainActivity$$Finder.class文件public class MainActivity$$Finder implements Finder<MainActivity> { @Override public void inject(final MainActivity host, Object source, Provider provider) { host.tvInfo = (TextView)(provider.findView(source, 2131165309)); View.OnClickListener listener; listener = new View.OnClickListener() { @Override public void onClick(View view) { host.onClick(view); } }; provider.findView(source, 2131165219).setOnClickListener(listener); provider.findView(source, 2131165220).setOnClickListener(listener); } }
很明显这里就是我们平时写的findview啊,setOnclickLIstener等方法的具体实现。通过注解,然后自动生成代码,注入到我们需要的类中。就免去了很多的重复劳动力,而且不会影响代码的运行效率。
5.4 注册处理器
新建一个android的library,命名为viewfinder。实现ViewFinder的static的inject方法,用于注入代码。最后调用到注解处理器中生成的xxx$$Finder类的inject方法。其中这里xxx既是MainActivity。
6.总结下
这里我们再把整个过程理一遍。编译期间
processor模块里的自定义的MyProcessor类的process会扫描所有的注解,然后生成自定义的XXX$$Finder.class代码。
使用期间
首先使用注解@BindView(R.id.tv_info)以及@OnClick({R.id.bt_change, R.id.bt_reset}),
接着MainActivity的onCreate方法中调用
ViewFinder.inject(this);方法来注入编译期间生成的代码。
关于apt技术基本上也了解了,说了那么多其实把例子敲一遍就都明白了。
github源码例子点击这里
参考:
http://blog.chengyunfeng.com/?p=1021
http://blog.csdn.net/u011315960/article/details/64441120
http://blog.csdn.net/hj7jay/article/details/52180023
https://github.com/sockeqwe/annotationprocessing101
相关文章推荐
- Android应用开发学习之路I-Java技术篇
- Android OpenGL(二) 学习《Android 3D 游戏开发技术宝典 -openGL ES 2.0》
- 【Android开发学习之路】
- 【尚观】Android游戏与应用开发最佳学习之路_转载来学习Android
- Android开发学习之路-环境搭建
- 我的android开发学习之路
- Android学习开发之路~~系列教程
- Android开发学习笔记之反射技术
- Android开发学习笔记之通过反射技术修改listview的快速滑块图像
- Android 学习之路和App开发框架
- android开发学习之路(1)---- activity及intent基本详解(2)
- 【尚观】Android游戏与应用开发最佳学习之路_转载来学习Android
- Android开发学习之路-编程环境初探
- 工作学习笔记——Alljoyn技术、初试Android开发
- 免费学习android开发技术分享
- 一步一步的学习android应用开发到系统底层开发之android开发层次及所需技术
- Android开发学习之路-Log的使用
- Android技术讲座(2):系统概述和学习之路