介绍
上一节中介绍了IOC的概念,以及使用反射注入对象,但是反射的效率比较低效,所以butterKnife换成了注解处理器的方式,在编译期间生成一些需要的代码来完成注入任务。
这一节也使用注入的方式实现一下对象的注入。
实现-分析
1.为了通用性 我们需要编写两个module, 一个是annotation的module中定义所有的注解,一个是annotation-compiler处理所有注解。他们的依赖关系是app依赖annotation和annotation-compiler, annotation-compile依赖annotation。
2.定义一个接口IBinder,接口里边的方法是接收Activity
3.annotation-compile处理器中实现IBinder的方法,调用Activity的findViewById方法给注解的属性赋值。
详细步骤
1.创建module和添加依赖关系
annotation-compile和annotation都是java的api,所以都定义为Java Library,
三者的依赖关系是
annotation-compile依赖annotation,annotation-compile下的build.gradle添加:
implementation project(path: ':annotation')
app依赖annotation,注解处理器引用annotation-compile
app的build.gradle添加:
implementation project(':annotation')
annotationProcessor project(':annotation-compiler'
2.annotation中创建注解类BindView:
@Retention(RetentionPolicy.SOURCE)//源码阶段
@Target(ElementType.FIELD)//目标是属性字段
public @interface BindView {
int value();
}
3.在app module中创建IBinder接口
public interface IBinder<T> {
void bind(T t);
}
4.在annotation-compile中定义注解处理器类AnnotationProcessor并且处理注解
@AutoService(Processor.class)
public class AnnotationProcessor extends AbstractProcessor {
private Filer filer;
private Messager messager;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
filer = processingEnv.getFiler();
messager = processingEnv.getMessager();
}
/**
* 支持的注解类型
* @return 能够处理的注解类型列表
*/
@Override
public Set<String> getSupportedAnnotationTypes() {
return new TreeSet<String>(){{
add(BindView.class.getCanonicalName());
}};
}
/**
* 支持的jdk版本
* @return 最新版本
*/
@Override
public SourceVersion getSupportedSourceVersion() {
return super.getSupportedSourceVersion();
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
//Element元素集合;包含程序中所有元素 比如 包 类 方法 成员变量等;这里只有变量。
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(BindView.class);//app中使用该注解修饰所有元素
//这里得到的是app中所有的元素,需要进行分类整理,然后创建类。
Map<String, List<Element>> groupElements = groupElement(elements);
for (String className : groupElements.keySet()) {
writeFile(className, groupElements.get(className));
}
return true;
}
/**
* 将所有元素根据类进行分类整理
* @param elements 元素集合
* @return 整理后的元素集合
*/
private Map<String, List<Element>> groupElement(Set<? extends Element> elements){
Map<String, List<Element>> map = new HashMap<>();
for (Element element : elements) {
String className = element.getEnclosingElement().getSimpleName().toString();
List<Element> elementList = map.get(className);
if (elementList == null) {
elementList = new ArrayList<>();
map.put(className, elementList);
}
elementList.add(element);
}
return map;
}
private void writeFile(String className, List<Element> elements){
//生成文件
Writer writer = null;
try {
PackageElement packageElement = processingEnv.getElementUtils().getPackageOf(elements.get(0).getEnclosingElement());
String packageNameString = packageElement.getQualifiedName().toString();
messager.printMessage(Diagnostic.Kind.NOTE, "getPackageOf得到的包是:"+packageNameString);
JavaFileObject classFile = filer.createSourceFile(className + "_ViewBinding", packageElement);
writer = classFile.openWriter();
// package com.example.dn_butterknife;
writer.write("package "+packageNameString+";\n");
// import com.example.dn_butterknife.IBinder;
writer.write("import "+packageNameString+".IBinder;\n");
// public class MainActivity_ViewBinding implements IBinder<com.example.dn_butterknife.MainActivity>{
writer.write("public class "+className+"_ViewBinding implements IBinder<"+packageNameString+"."+className+"> {\n");
// @Override
writer.write("@Override\n");
// public void bind(com.example.dn_butterknife.MainActivity target) {
writer.write("public void bind("+packageNameString+"."+className+" target) {\n");
// target.tvText=(android.widget.TextView)target.findViewById(2131165325);
for (Element fieldElement : elements) {
//属性名字
String fieldName = fieldElement.getSimpleName().toString();
writer.write("target."+fieldName+"=");
//控件的类型
String typeName = fieldElement.getKind().name();//这里得到的是这个元素的类型 比如:FIELD METHOD TYPE等等
messager.printMessage(Diagnostic.Kind.NOTE, typeName);
TypeMirror typeMirror = fieldElement.asType();
writer.write("("+typeMirror+")");
//资源id
int viewId = fieldElement.getAnnotation(BindView.class).value();
writer.write("target.findViewById("+viewId+");\n");
}
writer.write("}\n}");
} catch (IOException e) {
e.printStackTrace();
}finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
使用@AutoService 注册该类是注解处理器,要使用@AutoService 需要在build.gradle中添加依赖:
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6'
implementation'com.google.auto.service:auto-service:1.0-rc6'
具体实现代码中都有注释。
5.生命一个方法利用多态性调用编译器生成的实现类
public class MelonButterknife {
public static <T> void bind(T appCompatActivity) {
String name = appCompatActivity.getClass().getName()+"_ViewBinding";
try {
Class<?> clazz = Class.forName(name);
IBinder binder = (IBinder) clazz.newInstance();
binder.bind(appCompatActivity);
} catch (Exception e) {
e.printStackTrace();
}
}
}
6.在Activity中使用注解和调用绑定
public class MainActivity extends AppCompatActivity {
@BindView(R.id.text1)
TextView text1;
@BindView(R.id.text2)
TextView text2;
@BindView(R.id.text3)
TextView text3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MelonButterknife.bind(this);
text2.setText("早上好");
text3.setText("晚上好");
text1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, SecondActivity.class));
}
});
}
}
SecondActivity代码是:
public class SecondActivity extends AppCompatActivity {
@BindView(R.id.text3)
TextView textView3;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
MelonButterknife.bind(this);
textView3.setText("today");
}
}
下一步编译运行,会在如下目录看到生成的文件:

总结
这种方式是通过注解处理器生成一个实现绑定方法的类,这种硬编码生成辅助类是在编译期完成的,所以比运行期反射要高效。
网友评论