-
一小时搞明白注解处理器(
Annotation
Processor Tool
)
什么是注解处理器?
注解处理器是(
Annotation
Processor
)是
javac
的一个工具,用来在编译时扫描和
编译和处理注解
(
Annotation
)
。
你可以自己定义注解和注解处理器去搞一些事情。
一个注解
处
理器它以
Java
代码或者(编译过的字节码)作为输入,生成
文件(通常是
java
文件)
。这
p>
些生成的
java
文件不能修改,
并且会同其手动编写的
java
代码一样会被<
/p>
javac
编译。
看到这
里加上之前理解,应该明白大概的过程了,就是把标记了注解的类,变量等作为输入内容,
经过注解处理器处理,生成想要生成的
java
代码
。
处理器
AbstractProcessor
p>
处理器的写法有固定的套路,继承
AbstractProcess
or
。如下:
[java]
view plain copy
在
CODE
上查看代码片派生到我的代码片
public
class MyProcessor extends AbstractProcessor {
@Override
public synchronized void
init(ProcessingEnvironment processingEnv) {
(processingEnv);
}
@Override
public Set
return null;
}
@Override
public SourceVersion
getSupportedSourceVersion() {
return Supported();
}
@Override
public
boolean
process(Set
extends
TypeElement>
annotations,
RoundEnvironment
roundEnv) {
return true;
}
}
init(ProcessingEnvironment
processingEnv)
被注解处理工具调用,
参数<
/p>
ProcessingEnvironment
提供了
Element
,
Filer
< br>,
Messager
等工具
getSupportedAnnotationTypes()
指定注解处理器是注册给那一个注解的,它是一个字符串的
集合,意味着可以支持多
个类型的注解,并且字符串是合法全名。
getSupportedSourceVersion
指定
Java
版本
process(Set extends TypeElement>
annotations, RoundEnvironment roundEnv)
这个也是最主
要的,
在这里扫描和处理你的注解并生成
Java
代码,
信息都在参数
RoundEnvironment
里了,
后面会介绍。
在
Java7
中还可以使用
[java]
view plain copy
在
CODE
上查看代码片派生到我的代码片
@SupportedSourceVersion(Supported())
@SupportedAnnotationTypes({
//
合法注解全名的集合
})
代替
getSupportedSourceVersion()
和
getSupportedAnnotationType() ,
没毛病,
还可以在注解
处理离器中使用注解。
注册注解处理器
p>
打
包
注
解
处
理
器
的
时
候
需
要
< br>一
个
特
殊
的
文
件
sor
在
META-INF/services
路径下
[plain] view
plain copy
在
CODE
上
查看代码片派生到我的代码片
--
----
com
------
example
--------
----
META-INF
------
services
--------
sor
打包进
s
or
的内容是处理器的合法全称,
多个处理器之间换
行。
[plain] view plain
copy
在
CODE
上查看代码片派
生到我的代码片
essorA
essorB
google
提供了一个注册处理器
的库
[plain] view plain copy <
/p>
在
CODE
上查看代码片派生到我的代码
片
compile 'e:auto-
service:1.0-rc2'
一个注解搞定:
[java]
view plain copy
在
CODE
上查看代码片派生到我的代码片
@AutoService()
public class MyProcessor extends
AbstractProcessor {
...
}
读到这里
ButterKnife<
/p>
用到的知识点我们都已经了解了
1.
自定义注解
2.
用注解处理器解析注解
3.
解析完成后生成
Java
< br>文件
BufferKnife
使用:
[java] view plain copy
在
CODE
上查看代码片派生到我的代码片
public class MainActivity extends
AppCompatActivity {
@Bind(_demo)
Button mRxJavaDemo;
@Override
protected void onCreate(Bundle
savedInstanceState) {
te(savedInstanceState);
setContentView(ty_main);
(this);
t(
}
}
然
后
p>
我
们
编
译
一
下
,
打
开
路
径
:
< br>/app/build/intermediates/classes/release/com/mi ng/rxdemo/MainActivity$$$$
这就是我们生成的
Java
文件,可以看到
Button
已经在
bind
里面初始化了。
[java] view plain copy
在<
/p>
CODE
上查看代码片派生到我的代码片
public class MainActivity$$$$ViewBinder
public
MainActivity$$$$ViewBinder() {
}
public void bind(Finder finder, T
target, Object source) {
View
view
=
(View)quiredView(source,
2131492944,
'mRxJavaDemo'
aDemo
=
(Button)ew(view,
2131492944,
'mRxJavaDemo'
}
public void unbind(T target) {
aDemo = null;
}
}
接下来我们创建一个项目,写一个简单的用注解绑定控件的例子
项目结构
[plain] view
plain copy
在
CODE
上
查看代码片派生到我的代码片
--
apt-demo
----
bindview-
annotation(Java Library)
----
bindview-api(Android
Library)
----
bindview-compiler(Java
Library)
----
app(Android App)
bindview-
annotation
注解声明
bindview-api
调用
Android SDK API
bindview-compiler
注解处理器相关
app
测试
App
1.
在
bindview-annotation
下创建一个
@BindView
注解,该注解返回一个值,整型,名字为
value
,用来表示控件
ID
。
[java] view plain copy
在
CODE
上查看代码片派生到我的代
码片
@Target()
@Retention()
public @interface BindView
{
/**
*
用来装
id
*
* @return
*/
int
value();
}
2.
在
bindview-compiler
中创建注解处理器
BindViewProcessor
并注册,做基本的初始化工
作。
[java] view plain copy
在
CODE
上查看代码片派生到我的代码片
@AutoService()
public class BindViewProcessor extends
AbstractProcessor {
/**
*
文件相关的辅助类
*/
private Filer mFiler;
/**
*
元素相关的辅助类
*/
private Elements
mElementUtils;
/**
*
日志相关的辅助类
*/
private Messager mMessager;
/**
*
解析的目标注解集合
*/
private Map
@Override
public
synchronized void init(ProcessingEnvironment
processingEnv) {
(processingEnv);
mElementUtils =
mentUtils();
mMessager = sager();
mFiler = er();
}
@Override
public Set
Set
p>
(onicalName());//
返回该注解处理器支持的注解
集合
return types;
}
@Override
public
SourceVersion getSupportedSourceVersion() {
return
Supported();
}
@Override
public
boolean
process(Set
extends
TypeElement>
annotations,
RoundEnvironment
roundEnv) {
return true;
}
}
<
/p>
是不是注意到了里面有个
Map
容器,<
/p>
而且类型是
AnnotatedClass
,
这是干啥的呢?这个很好
理解,
我
们在解析
XML
,
解析
Json
的时候数据解析完之后是不是要以对象的形式表示出来,
这里也一样,
@BindView
用来标记类成员,
一个类下可以有多个成员,好比一个
Activity
中可以有
多个控件,一个容器下有多个控件等。如下:
[java]
view plain copy
在
CODE
上查看代码片派生到我的代码片
package
import il;
import ame;
import le;
import Spec;
import terizedTypeName;
import me;
import ec;
import ist;
import
import er;
import ement;
import ts;
/**
* Created by
mingwei on 12/10/16.
* CSDN:
/u013045971
* Github:
/gumingwei