使用流程
在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_compilerannotation_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')
感觉有帮助朋友可以随机打赏喔 谢谢