上篇文章说道IOC依赖注入,但是这种注入方式是在运行时处理注解,效率较低。今天给大家介绍butterknife模式的依赖注入。
首先要了解注解处理器
继承自AbstractProcessor,在编译期间,就会遍历AbstractProcessor的所有子类,把这些类可接受的注解所有对应TypeElement
(注意是TypeElement,即class这个节点)传到process
方法
有四个方法是你需要注意的
1.public synchronized void init(ProcessingEnvironment processingEnvironment) 初始化方法,可以获取文件写入的类
Filer,编译时信息输出的类Messager,等等...
2.public SourceVersion getSupportedSourceVersion(),设置JDK的版本号,一般设置为当前使用的就OK:
SourceVersion.latestSupported()
3.public Set<String> getSupportedAnnotationTypes(),设置你可以处理的注解
4.public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment),这个也是最关键的一个,编译时如果检测到你说设置的注解,就会调用此方式。
接下来先看一下项目结构
1.annotion_lib这是一个java的moudle,里面存放注解。
2.compile_lib这是方注解处理器的,依赖annotion_lib这个moudle.
3.init_lib,android moudle存放初始化的类
4.app,android moudle存放正常android代码。
接下来先看annotion_lib
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.FIELD)
public @interface BindView {
int value();
}
此时注解是为了在编译时生成我们需要的文件,所以注解的生命周期就用RetentionPolicy.SOURCE就可以。
接下来看compile_lib
需要用到 gool 的auto-service自动生成java文件的库。
,
创建java类MyProcessor并继承自AbstractProcessor,并且添加类注解
@AutoService(Processor.class)
我们在init方法中初始化了filer 和messager
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
filer = processingEnvironment.getFiler();
messager = processingEnvironment.getMessager();
}
getSupportedSourceVersion中制动jdk版本号
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
getSupportedAnnotationTypes指定需要处理的注解
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> set = new HashSet<>();
set.add(BindView.class.getCanonicalName());
set.add(OnClick.class.getCanonicalName());
return set;
}
我们需要一个中间类,来处理activity中属性和事件的绑定
假设这个类就是
其中IBInder是init_lib中定义的接口
接下来就是
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment)
方法,
这个方法就不得不说关键的四个类
Element:所添加的注解的节点
TypeElement
:就是注解所在的类
VariableElement:所注解的属性
ExecutableElement:注解所在的方法
首先我们先获取到注解所在的节点
Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(BindView.class);//获取所有被bindView所注解的element
我们需要根据每个activity生成相对应的文件,因此创建一个map来存放每个activity所携带的参数
Map<String, List<VariableElement>> maps = new HashMap<>();
接下来需要把节点按照不同的activity存放起来
接下来就是具体的下入文件了
把上面所提到的中间文件一行一行写入进去。
接下来就是init_lib,在这里通过反射来创建我们生成的这个中间类,进行绑定。
接下来就是activity的初始化
接下来就是点击build中的rebuild project
接下来会在activity的build中生成我们需要的文件