扔物线学习笔记啊
目标 小试牛刀:要实现类似ButterKnife 绑定视图
public class MainActivity extends AppCompatActivity {
@BindView(R.id.textView) TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InnerBinding.bind(this);
textView.setText("卧龙凤雏");
}
}
一 反射加注解
简单实现 1.同模块
public class InnerBinding {
public static void bind(MainActivity activity) {
activity.textView = activity.findViewById(R.id.textView);
}
}
添加反射
public class InnerBinding {
public static void bind(Activity activity) {
//activity.textView = activity.findViewById(R.id.textView);
//如果有多个控件 TextViw ImageView 需要反射
// 1.遍历所有的Field
for (Field field:activity.getClass().getDeclaredFields()){
//2.如果Filed 是BindView注解(前面有BindView注解的作用就来了)
BindView bindView = field.getAnnotation(BindView.class);
//3.如果BindView非空,拿到值(例如R.id.textView)
if (bindView!=null){
try {
//4.赋值
field.set(activity,activity.findViewById(bindView.value()));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
移动到lib-reflection模块,运行报错
因为此时TextView不是public,需要扩大反射权限
//5.扩大访问权限
field.setAccessible(true);
完成通过反射bind
ButterKnife 不是依赖注入,是视图绑定
二 工具类加反射
通过在一个MainActivityBinding完成绑定操作,Binding只实例化MainActivityBinding
MainActivityBinding.java
public class MainActivityBinding {
//初始化就设置
public MainActivityBinding(MainActivity activity) {
activity.textView = activity.findViewById(R.id.mTv);
}
}
Binding.java
public class Binding {
public static void bind(Activity activity){
try {
//获取类
Class bindingClass = Class.forName(activity.getClass().getCanonicalName() + "Binding");
//获取构造方法
Constructor constructor = bindingClass.getDeclaredConstructor(activity.getClass());
constructor.newInstance(activity);
} catch (ClassNotFoundException | NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Binding.bind(this);
textView.setText("卧龙凤雏");
}
}
三 反射加注解生成工具类
1.要通过注解自动生成 MainActivityBinding
- 1.1创建一个 Module java or kotlin library 例如lib_processor
- 1.2配置 固定的文件目录格式 resources =》META-INF=》services=》javax.annotation.processing.Processor 添加映射
- 1.3app模块添加依赖 annotationProcessor
- 1.4专门为注解创建一个模块 例如 lib_annoration 让后其他需要用的地方添加依赖
项目结构
- 生成代码工具 Filer
- 用 javapoet 来生成的代码
BindingProcessor.java
/**
* 注解处理的处理
* 生成代码 processor
* 在编译前执行
*/
public class BindingProcessor extends AbstractProcessor {
Filer filer;
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
filer = processingEnvironment.getFiler();
}
/**
* package com.example.annotation;
*
* public class MainActivityBinding {
* public MainActivityBinding(MainActivity activity) {
* activity.textView = activity.findViewById(R.id.mTv);
* }
* }
*/
/**
* 进行具体的注解处理
*
* @param set
* @param roundEnvironment
* @return
*/
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
for (Element element : roundEnvironment.getRootElements()) {
String packageStr = element.getEnclosingElement().toString();
String classStr = element.getSimpleName().toString();
ClassName className = ClassName.get(packageStr,classStr+"Binding");
MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC)
.addParameter(ClassName.get(packageStr,classStr),"activity");
boolean hasBinding = false;
for (Element enclosedElement:element.getEnclosedElements()){
if (enclosedElement.getKind() == ElementKind.FIELD) {
BindView bindView = enclosedElement.getAnnotation(BindView.class);
if (bindView!=null){
hasBinding = true;
constructorBuilder.addStatement("activity.$N = activity.findViewById($L)",
enclosedElement.getSimpleName(),bindView.value());
}
}
}
TypeSpec builtClass = TypeSpec.classBuilder(className)
.addModifiers(Modifier.PUBLIC)
.addMethod(constructorBuilder.build())
.build();
if (hasBinding){
try {
JavaFile.builder(packageStr,builtClass)
.build().writeTo(filer);
} catch (IOException e) {
e.printStackTrace();
}
}
}
return false;
}
/**
* 进行注解处理的类型
*
* @return
*/
@Override
public Set<String> getSupportedAnnotationTypes() {
return Collections.singleton(BindView.class.getCanonicalName());
}
}
BindView.java
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.FIELD)
public @interface BindView {
int value();
}