butterKnife
- 强大的View 绑定和时间处理功能可以帮助程序简化代码节省开发时间
- 能够方便你的处理adapter 里面的viewholder绑定问题
- 使用过程中不会影响app运行的效率和性能 因为注解作用在编译器
- 使用butterKnife 使我们的代码更清晰,可读性更强
使用流程
在app build.gradle文件下面添加
implementation'com.jakewharton:butterknife:9.0.0' //注解
annotationProcessor'com.jakewharton:butterknife-compiler:9.0.0'//注解处理器
compilOptions{
sourceCompatibility 1.8
targetCompatibility 1.8
}
实现原理
ButterKnife 的原理就是利用注解和注解处理器针对每个activity都生成一个相对应的类将原本
需要进行绑定的view或者点击事件以及资源ID绑定等都写入相对应的类中,然后调用相应的类中的方法,
从而相当于原本需要程序员手写的代码现在由butterKnife自动实现了
注解和注解处理器
注解作用 :用于标记没有什么实际的作用 仅仅作用于区分
注解处理器作用: 处理相关的注解
注解处理器怎么声明 在注解处理器moudle中build.gradle添加下面的
//注册我们的注解 告诉JVM 我们这个moudle里面自定义注解处理器 androidstudio 小于3.4
implementation 'com.google.auto.service:auto-service:1.0-rc3'
//androidStudio 版本大于3.4用下面的这种形式
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
compileOnly 'com.google.auto.service:auto-service:1.0-rc4'
代码手写实现ButterKnife
首先创建两个javaLibrary
annotations
annotation_compiler
annotation_compiler下面的类
要添加依赖喔
implementation project(path: ':annotations')
package com.example.annotation_compiler;
import com.example.annotations.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.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(Process.class) // 注册注解处理器 就是gradle文件添加依赖的原因
public class AnnotationComiler extends AbstractProcessor {
// 生成文件的对象
Filer filer;
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
filer = processingEnvironment.getFiler();
}
/**
* 声明这个注解处理器需要处理的注解
* @return
*/
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> types = new HashSet<>();
types.add(BindView.class.getCanonicalName());
return types ;
}
/**
* 声明当前注解处理器支持的java版本
* @return
*/
@Override
public SourceVersion getSupportedSourceVersion() {
return processingEnv.getSourceVersion();
}
/**
* 在这个方法里面我们就要去写文件
* @param set
* @param roundEnvironment
* @return
*/
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
// 拿到整个模块中《app》用到BindView的注解的节点
Set<? extends Element> elementsAnnotatedWith =
roundEnvironment.getElementsAnnotatedWith(BindView.class);
// key -- activity名字
Map<String, List<VariableElement>> map = new HashMap<>();
for (Element element:elementsAnnotatedWith) {
//获取到成员变量的节点 也就是控件
VariableElement variableElement= (VariableElement)element;
String activityName = variableElement.getEnclosingElement().getSimpleName().toString(); // 获取到activity名字
List<VariableElement> 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<String> iterator = map.keySet().iterator();
while (iterator.hasNext()){
String activityName = iterator.next();
List<VariableElement> variableElements = map.get(activityName); // 得到的是 activity对应的控件
//通过控件的成员变量节点 获取到他的上一个节点 也就是类节点
TypeElement enclosingElement = (TypeElement)variableElements.get(0).getEnclosingElement();
// 通过成员变量的到包名
String packageName = processingEnv.getElementUtils().getPackageOf(enclosingElement).toString();
try {
JavaFileObject sourceFile = filer.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");
writer.write("@Override\n" +
" public void bind("+packageName+"."+activityName+" target) {");
//遍历所有的成员变量 添加代码
for (VariableElement variableElement :variableElements) {
//获取到控件的名字
String variableName = variableElement.getSimpleName().toString();
//获取到控件的id
int id = variableElement.getAnnotation(BindView.class).value();
//获取到这个控件的类型
TypeMirror typeMirror = variableElement.asType();
writer.write("target."+variableName+"=("+typeMirror+")target.findViewById("+id+");\n");
}
writer.write("}\n}\n");
} catch (IOException e) {
e.printStackTrace();
}finally {
if (writer!=null){
try {
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return false;
}
}
annotations下面的类
package com.example.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD) // 声明该注解是作用在什么上面的 也就是作用域 这个是属性的
@Retention(RetentionPolicy.SOURCE) //声明定义的注解声明周期 这边是源码期 源码时期 编译器 运行期 java-->class -->run
public @interface BindView {
int value();
}
模仿ButterKnife
package com.example.myapplication;
import android.app.Activity;
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();
}
}
}
具体用法
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import com.example.annotations.BindView;
public class MainActivity extends AppCompatActivity {
@BindView(R.id.textview)
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ButterKnife.bind(this);
setContentView(R.layout.activity_main);
}
}
----记得添加依赖 ————————
annotationProcessor project(path: ':annotation_compiler')
implementation project(path: ':annotations')
感觉有帮助朋友可以随机打赏喔 谢谢