ButterKnife是一款通过注解,绑定控件的id,String,Bitmap等资源id的注解框架 同时ButterKnife是一个编译时框架,所以对代码性能影响几乎为0
使用注解之前: 首先要新建java的library,然后注册注解(添加注解的依赖),告诉jvm我们这个module里面自定义注解处理器
implementation 'com.google.auto.service:auto-service:1.0-rc3'
//如果AS版本是3.4以上 gradle 5.1.1-all 使用以下依赖
//annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
//compileOnly 'com.google.auto.service:auto-service:1.0-rc4'
implementation project(':annotation')
我们新建两个java的lib 一个叫做annotation,另一个叫做annotation_complier,如图添加依赖
拿BindView功能来说,ButterKnife有个BindView的接口
我们在annotation下面新建一个类叫做BindView
@Target(ElementType.FIELD)//申明注解的类型,是放在什么上面的
@Retention(RetentionPolicy.SOURCE)//声明注解的生命周期 java-class-run 编译期CLASS 运行期RUNTIME 源码期SOURCE,
public @interface BindView {
int value();
}
在annotation_complier新建一个类叫做AnnotationCompilier
package com.dhd.annotation_complier;
import com.dhd.annotation.BindView;
import com.google.auto.service.AutoService;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.tools.JavaFileObject;
/**
* 注解处理器,生成activity相对应的类
*/
@AutoService(Processor.class)//注册注解器
public class AnnotationCompilier extends AbstractProcessor {
//生成文件对象
Filer mFiler;
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
mFiler = processingEnvironment.getFiler();
}
/**
* @return 申明注解处理器要处理的注解
*/
@Override
public Set getSupportedAnnotationTypes() {
Set types = new HashSet<>();
types.add(BindView.class.getCanonicalName());//把要处理的注解添加到集合
return types;
}
/**
* @return 申明当前注解处理器支持的版本
*/
@Override
public SourceVersion getSupportedSourceVersion() {
return processingEnv.getSourceVersion();
}
/**
* 写文件(acitivy或者frag的注解类)
*
* @param set
* @param roundEnvironment
* @return
*/
@Override
public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) {
//拿到整个模块中使用到Bindview的节点
Set extends Element> elementsAnnotatedWith = roundEnvironment.getElementsAnnotatedWith(BindView.class);
Map> map = new HashMap<>();
for (Element element : elementsAnnotatedWith) {
//获取成员变量的节点(控件)
VariableElement variableElement = (VariableElement) element;
String activityName = variableElement.getEnclosingElement().getSimpleName().toString();
List variableElements = map.get(activityName);
if (variableElements == null) {
variableElements = new ArrayList<>();
map.put(activityName, variableElements);
}
variableElements.add(variableElement);
}
if (map.size() > 0) {
Writer writer = null;
Iterator iterator = map.keySet().iterator();
while (iterator.hasNext()) {
String activityName = iterator.next();
List variableElements = map.get(activityName);
//通过成员变量获取上一个节点的类节点
Element enclosingElement = variableElements.get(0).getEnclosingElement();
//通过成员变量得到包名
String packageName = processingEnv.getElementUtils().getPackageOf(enclosingElement).toString();
try {
JavaFileObject sourceFile = mFiler.createSourceFile(packageName + "." + activityName + "_ViewBinding");
writer = sourceFile.openWriter();
writer.write("package " + packageName + ";\n");
writer.write("import " + packageName + ".IBinder;\n");
writer.write("public class " + activityName + "_ViewBinding implements IBinder<" + packageName + "." + activityName + ">{\n\n");
writer.write(" @Override\n" + " public void bind(" + packageName + "." + activityName + " target) {\n");
for (VariableElement variableElement : variableElements) {
//获取控件的名字
String variableName = variableElement.getSimpleName().toString();
//获取控件ID
int id = variableElement.getAnnotation(BindView.class).value();
//获取控件的类型
TypeMirror typeMirror = variableElement.asType();
writer.write(" targer." + variableName + "=(" + typeMirror + ")target.findViewById(" + id + ");\n");
}
writer.write(" }\n}\n");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return false;
}
}
自定义注解需要继承AbstractProcessor类,并且申明@AutoService(Processor.class)为Processor.class 在实现类里面需要复写几个方法 第一个是初始化Filer的init方法 第二个是复写支持的资源版本getSupportedSourceVersion方法 第三个是getSupportedAnnotationTypes方法,该方法返回支持的注解类型集合(比如BindView,BindString,BingBitmap等) 最后一个也是我们处理很多业务逻辑的以及写入文件的方法process方法,这个方法我们可以拿到调用自定义注解的类名,类里面的方法,控件等等 然后通过Writer写入文件,该java文件实现初始化接口的方法,在初始化方法比如bind中去findViewById(),写入的代码会在编译时生成对应的java文件; 然后在activity中调用的时候需要提供一个初始化的方法,比如叫ButterKnife.bind(this), 那这个bind方法通过反射的方式拿到初始化方法接口的实例,传入调用者的上下文this,即可实现绑定
public class ButterKnife {
public static void bind(Activity activity) {
String name = activity.getClass().getName() + "_ViewBinding";
try {
Class> aClass = Class.forName(name);
IBinder iBinder = (IBinder) aClass.newInstance();
iBinder.bind(activity);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public interface IBinder {
void bind(T target);
}
最后在MainActivity中调用
public class MainActivity extends AppCompatActivity {
@BindView(R.id.textview)
TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
mTextView.setText("自定义注解");
}
}
整体来说主要是annotationProcessor的api使用,如果要实现BindString,BindBitmap,代码也是类似的