项目主要是为了让大家了解 写一个动态注入的框架 是怎么一个流程,都需要什么,怎么做。
大体思路
思路
编译期间,通过自定义处理器,动态生成代码
程序运行时,通过反射调用 动态生成的代码中的方法
最后达到绑定控件的目的
整体结构
整个项目需要三个model
app
java lib
android lib
java lib 中主要写处理器和注解,androdi lib 中写反射。处理器必须继承 AbstractProcessor ,而 AbstractProcessor 属于 javax , 所以需要建立两种项目
步骤
java lib(注解和控制器)
结构
MyProcessor 核心处理类
ClassEntey 类的抽象类 (包括 路径、类名、属性集合)
AttrEntey 属性抽象类 (包括 属性名、属性值、属性类型)
处理器
注册
处理器的作用就是在编译期间执行我们想生成的代码,javac会自动寻找继承了 AbstractProcessor 的类
注册处理器(两种方式)
方式一
在main文件下创建(不推荐)
resources/META-INF/javax.annotation.processing.Processor在文件中写
格式:包名+“.”+类名
com.example.MyProcessor
复制代码
方式二
依赖
dependencies {
compile 'com.google.auto.service:auto-service:1.0-rc2'
}
复制代码
在继承了 AbstractProcessor 的类上面写
@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor
复制代码
实现
创建注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.CLASS)
public @interface BindView {
int value();
}
复制代码
在继承 AbstractProcessor 的类中,实现如下三个方法
方法名
作用getSupportedAnnotationTypes()
需要处理的那些注解
getSupportedSourceVersion()
限制版本
process()
核心函数,在这个里面做处理
主要介绍process()方法
当javac 查询到所有在getSupportedAnnotationTypes()里面注册过的注解后,才会调用process()方法
process()方法有两个参数
public boolean process(Set annotations, RoundEnvironment roundEnv)
复制代码
着重介绍第二个,第二个参数代表所有和这个注解有关信息的集合,如下
例子
所在路径
cxy.com.myviewbind.Main2Activity
复制代码
@BindView(R.id.button)
Button button ;
复制代码
方法名
含义roundEnv.getSimpleName()
button
roundEnv.getEnclosingElement()
cxy.com.myviewbind.Main2Activity
roundEnv.getAnnotation()
R.id.button 所对应的整数值
roundEnv.asType()
android.widget.Button
有这些就可以生成我们需要的类了
我们看一下process()中都做了什么
@Override
public boolean process(Set annotations, RoundEnvironment roundEnv) {
// 以activity名为key,类的抽象类为value
Map map = new LinkedHashMap<>();
//判断是否为BindView 注解
for (Element element : roundEnv.getElementsAnnotatedWith(BindView.class)) {
//判断是否为变量
if (element.getKind() == ElementKind.FIELD) {
String className = element.getEnclosingElement().toString();
//判断当前界面在map结合中是否存在,不存在则添加
ClassEntey classEntey = map.get(className);
if (classEntey == null) {
String parkageNmae = className.substring(0, className.toString().lastIndexOf("."));
String classSimpleName = className.substring(
className.lastIndexOf(".") + 1, className.length()
) + "_BindView";
classEntey = ClassEntey.create(classSimpleName, parkageNmae);
map.put(element.getEnclosingElement().toString(), classEntey);
}
//activity可能存在多个控件属性,创建属性抽象类并赋值,最后添加进当前界面为key的抽象类中
AttrEntey attrEntey = AttrEntey.create(
element.getSimpleName().toString(),
element.asType().toString().substring(
element.asType().toString().lastIndexOf(".") + 1, element.asType().toString().length()
),
element.getAnnotation(BindView.class).value()
);
classEntey.addAttr(attrEntey, processingEnv);
}
}
//以上,所有的属性已经获取获取
//以下,把所有的数据写成文件
//
for (Map.Entry entry : map.entrySet()) {
try {
List arrts = entry.getValue().getArrts();
Set setImp = new HashSet<>();
//循环获取出所有需要导入的包
for (AttrEntey entey : arrts) {
setImp.add(entey.getType());
}
//写文件
createJava(entry.getValue(), setImp);
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
复制代码
createJava为写文件的方法,为了更容易读懂,没有用javapoet,使用拼接字符串的方式完成写文件操作
createJava
private void createJava(ClassEntey entry, Set setImp) throws Exception {
JavaFileObject filerClassFile = filer.createSourceFile(entry.getParkageName() + "." + entry.getClassSimpleName(), new Element[]{});
Writer writer = filerClassFile.openWriter();
PrintWriter pw = new PrintWriter(writer);
···
pw.flush();
writer.close();
}
复制代码
简单说一下 filer :是写文件用的,在init方法中获取
android lib(反射生成的文件)
依赖刚才的java lib
没什么难度,不说了
android app(项目文件)
使用方式和butterknife 一样
public class MainActivity extends AppCompatActivity {
@BindView(R.id.edittext)
EditText edittext;
@BindView(R.id.button)
Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyBindView.bind(this);
edittext.setText("界面1");
button.setText("跳转至第二个界面");
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(MainActivity.this, Main2Activity.class));
}
});
}
}
复制代码
-END-
哪里写的不清晰可以给我留言,我会第一时间修改
参考文档