butterknife工具在项目中比较常用
分三个模块模块之间的UML关系图
其中
butterknife-annotations
butterknife-compiler
为Java工程
butterknife
为android工程
有很多工能都没用到
仿butterknife自定义BindView
一、创建三个library
1.compiler
@AutoService(Processor.class)
public class ButterKnifeProcessor extends AbstractProcessor {
/**
* 用来指定支持的 AnnotationTypes
*
* @return
*/
@Override
public Set getSupportedAnnotationTypes() {
Set types = new LinkedHashSet<>();
for (Class extends Annotation> annotation : getSupportedAnnotations()) {
types.add(annotation.getCanonicalName());
}
return types;
}
/**
* 参考了 ButterKnife 的写法
*
* @return
*/
private Set> getSupportedAnnotations() {
Set> annotations = new LinkedHashSet<>();
annotations.add(BindView.class);
return annotations;
}
/**
* 用来指定支持的 SourceVersion
*
* @return
*/
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) {
// 调试打印
System.out.println("------------------------------------>");
System.out.println("------------------------------------>");
return false;
}
}
添加依赖
compile 'com.google.auto.service:auto-service:1.0-rc3'
compile 'com.squareup:javapoet:1.8.0'
compile project(':annotations')
compile files('libs/tools.jar')
如果我们在代码的任何地方有注解,都会来到 process 这个方法里面。
@Override
public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) {
// 调试打印
// System.out.println("------------------------------------>");
// System.out.println("------------------------------------>");
Set extends Element> bindViewElements = roundEnvironment.getElementsAnnotatedWith(BindView.class);
// 解析 Element
Map> analysisElementMap = new LinkedHashMap<>();
for (Element bindViewElement : bindViewElements) {
Element enclosingElement = bindViewElement.getEnclosingElement();
List elements = analysisElementMap.get(enclosingElement);
if (elements == null) {
elements = new ArrayList<>();
analysisElementMap.put(enclosingElement, elements);
}
elements.add(bindViewElement);
}
// 生成 java 类
for (Map.Entry> entry : analysisElementMap.entrySet()) {
Element enclosingElement = entry.getKey();
List elements = entry.getValue();
String classNameStr = enclosingElement.getSimpleName().toString();
ClassName unbinderClassName = ClassName.get("com.butterknife", "Unbinder");
// 组装类: xxx_ViewBinding implements Unbinder
TypeSpec.Builder typeSpecBuilder = TypeSpec.classBuilder(classNameStr + "_ViewBinding")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addSuperinterface(unbinderClassName);
ClassName callSuperClassName = ClassName.get("android.support.annotation", "CallSuper");
// 组装unbind 方法
MethodSpec.Builder unbindMethodBuilder = MethodSpec.methodBuilder("unbind")
.addAnnotation(Override.class)
.addAnnotation(callSuperClassName)
.addModifiers(Modifier.PUBLIC)
.returns(TypeName.VOID);
ClassName uiThreadClassName = ClassName.get("android.support.annotation", "UiThread");
ClassName parameterClassName = ClassName.bestGuess(classNameStr);
// 组装构造函数: public xxx_ViewBinding(xxx target)
MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder()
.addAnnotation(uiThreadClassName)
.addModifiers(Modifier.PUBLIC)
.addParameter(parameterClassName, "target");
// 添加 target.textView1 = Utils.findViewById(target,R.id.tv1);
for (Element bindViewElement : elements) {
String filedName = bindViewElement.getSimpleName().toString();
ClassName utilClassName = ClassName.get("com.butterknife", "Utils");
int resId = bindViewElement.getAnnotation(BindView.class).value();
constructorBuilder.addStatement("target.$L = $T.findViewById(target,$L)",
filedName, utilClassName, resId);
}
typeSpecBuilder.addMethod(constructorBuilder.build());
typeSpecBuilder.addMethod(unbindMethodBuilder.build());
try {
// 写入生成 java 类
String packageName = mElementUtils.getPackageOf(enclosingElement).getQualifiedName().toString();
JavaFile.builder(packageName, typeSpecBuilder.build())
.addFileComment("ButterKnife自动生成")
.build().writeTo(mFiler);
} catch (IOException e) {
e.printStackTrace();
System.out.println("翻车了");
}
}
return false;
}
2.annotations
创建BindView
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.CLASS)
public @interface BindView {
int value();
}
3.butterknife
创建Unbinder
public interface Unbinder {
@UiThread
void unbind();
Unbinder EMPTY = new Unbinder() {
@Override
public void unbind() {
}
};}
创建Utils
public class Utils {
public static final T findViewById(Activity activity, int viewId) {
return (T) activity.findViewById(viewId);
}
}
创建 ButterKnife
public class ButterKnife {
private ButterKnife() {
throw new AssertionError("No instances.");
}
public final static Unbinder bind(Activity activity) {
String viewBindingClassName = activity.getClass().getName() + "_ViewBinding";
try {
Class extends Unbinder> viewBindingClass = (Class extends Unbinder>) Class.forName(viewBindingClassName);
Constructor extends Unbinder> viewBindingConstructor = viewBindingClass.getDeclaredConstructor(activity.getClass());
Unbinder unbinder = viewBindingConstructor.newInstance(activity);
return unbinder;
} catch (Exception e) {
e.printStackTrace();
}
return Unbinder.EMPTY;
}
}
二、使用
1.module的builder
依赖
compile project(':annotations')
compile project(':butterknife')
apt project(':compiler')
添加
apply plugin: 'com.neenbedankt.android-apt'
2.工程的builder
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
3.使用
public class MainActivity extends Activity {
@BindView(R.id.tv_text)
TextView textView1;
private Unbinder bind;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bind = ButterKnife.bind(this);
textView1.setText("1111111111");
}
@Override
protected void onDestroy() {
super.onDestroy();
bind.unbind();
}
}