butterknife 非androidx支持 android butterknife原理
转载
抛出问题:
1.Butterknife是干什么的?
2.我们如何去看Butterknife框架
3.如果我们自己写一个类似Butterknife框架,我们如何去做?
ButterKnife是一个专注于Android系统的View注入框架,可以减少大量的findViewById 以及 setOnClickListener代码,可视化一键生成。
|
解决问题:
2.首先我们要明白 butterknife-annotations ,butterknife-compiler是干什么的?
我们从butterknife-annotations点击发现:
import android.support.annotation.IdRes;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.CLASS;
/**
* Bind a field to the view for the specified ID. The view will automatically be cast to the field
* type.
* <pre><code>
* {@literal @}BindView(R.id.title) TextView title;
* </code></pre>
*/
@Retention(CLASS) @Target(FIELD)
public @interface BindView {
/** View ID to which the field will be bound. */
@IdRes int value();
}
|
这里的注解BideView我们会在我们的Activity 绑定控件使用到 eg:
butterknife-compiler点击我们会发现:
下面我们就具体解释他们的作用:
| 作用
|
AbstractProcessor / Annotation Processor Tool (apt)
| 是javac的一个工具,用来在编译时扫描和编译和处理注解(Annotation)。你可以自己定义注解和注解处理器去搞一些事情。一个注解处理器它以Java代码或者(编译过的字节码)作为输入,生成文件(通常是java文件)。这些生成的java文件不能修改,并且会同其手动编写的java代码一样会被javac编译。
|
RetentionPolicy.SOURCE
| 编译之后抛弃,存活的时间在源码和编译时
|
RetentionPolicy.CLASS
| 保留在编译后class文件中,但JVM将会忽略(对于 底层系统开发-开发编译过程 使用) apt中source和class都一样
|
RetentionPolicy.RUNTIME
| 能够使用反射读取和使用(运行时)
|
3.butterknife使用
配置
(1).在工程目录下 的build.gradle 添加apt插件classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
|
(2). 在app 目录下的build.gradle 应用 添加apt插件apply plugin: 'com.neenbedankt.android-apt'
|
(3).依赖 具有apt 处理的moudle 这里不是compile 而是aptapt project(':butterknife-compiler')
|
二.具体应用
1.创建模块butterknife-annotion
2.创建模块注解处理器butterkniffe-complier
注解处理器的作用上面我们已经说过了 就是处理注解生成Java文件 和javapoet类似
@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes("com.dongnao.butterknife_annotion.BindView")
public class ButterKniffeProcess extends AbstractProcessor {
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> types = new LinkedHashSet<>();
types.add(BindView.class.getCanonicalName());
return types;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
|
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
//
System.out.println("-----------------process-----------------------");
//VariableElement 成员遍历
Set<? extends Element> elementSet = roundEnvironment.getElementsAnnotatedWith(BindView.class);
// 区分 key是activity 全类名=包名+类名 值 成员变量集合
Map<String, List<VariableElement>> cacheMap = new HashMap<>();
//MainActivity.class 标签
for (Element element : elementSet) {
// 全类名=包名+类名
VariableElement variableElement = (VariableElement) element;
String activityName = getActivityName(variableElement);
List<VariableElement> list = cacheMap.get(activityName);
if (list == null) {
list = new ArrayList<>();
cacheMap.put(activityName, list);
}
// 分类
list.add(variableElement);
System.out.println("--------->" + variableElement.getSimpleName().toString());
}
// 2 为每一个activity生成 Class
//
Iterator iterator = cacheMap.keySet().iterator();
while (iterator.hasNext()) {
//得到mainActivity名字
String activityName = (String) iterator.next();
//得到mainActivity 控件成员变量的集合
List<VariableElement> caheElements = cacheMap.get(activityName);
String newActivityBinder = activityName + "$ViewBinder";
Filer filer = processingEnv.getFiler();
try {
JavaFileObject javaFileObject = filer.createSourceFile(newActivityBinder);
String packageName = getPackageName(caheElements.get(0));
Writer writer = javaFileObject.openWriter();
String activitySimpleName = caheElements.get(0).getEnclosingElement().getSimpleName().toString() + "$ViewBinder";
writeHeader(writer, packageName, activityName, activitySimpleName);
//中间部分
for (VariableElement variableElement : caheElements) {
BindView bindView = variableElement.getAnnotation(BindView.class);
int id = bindView.value();
String fieldName = variableElement.getSimpleName().toString();
TypeMirror typeMirror = variableElement.asType();
// TextView
writer.write("target." + fieldName + "=(" + typeMirror.toString() + ")target.findViewById(" + id + ");");
writer.write("\n");
}
//结尾部分
writer.write("\n");
writer.write("}");
writer.write("\n");
writer.write("}");
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
Element:
//获得父节点 (类)
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
上面的代码其实是解析注解生成如下代码: |
package com.example; // PackageElement
获取包名processingEnv.getElementUtils().getPackageOf(typeElement).getQualifiedName().toString();
public class Dog{ // TypeElement 获取类名
private int age; // VariableElement 获取属性
public Dog() {} // ExecuteableElement
public void setA ( ) {} // ExecuteableElement
}
-----------------process-----------------------
-------packageName--------com.butterknifeframwork
--------->test
-------packageName--------com.butterknifeframwork
--------->textView
-------packageName--------com.butterknifeframwork
--------->textView
-------packageName--------com.butterknifeframwork
-------packageName--------com.butterknifeframwork
-------packageName--------com.butterknifeframwork
|
3.测试:绑定成功
本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。