反射:
Class.forName("com.mysql.jdbc.Driver");
在编写代码,编译的时候,这个类没有,但是在运行的时候,这个Driver.class类有。
Mirror模块
让java源文件在编译的时候,可以访问
APT 命令行工具
1.编译过程中,需要获取哪些类的信息?
2.这些类的信息在哪里获取?
APT会访问AnnotationProcessor类,获取访问规则,然后访问符合规则的A类,访问到了A类的属性,方法集合,这些信息又会传给Process处理。
核心类代码
1、ViewInjectHandler.java
把RoundEnvironment类整理出一个Map
public class ViewInjectHandler implements AnnotationHandler {
ProcessingEnvironment mProcessingEnv;
@Override
public void attachProcessingEnv(ProcessingEnvironment processingEnv) {
mProcessingEnv = processingEnv;
}
@Override
public Map<String,List<VariableElement>> handleAnnotation(RoundEnvironment roundEnv){
Map<String, List<VariableElement>> annotationMap = new HashMap<String, List<VariableElement>>();
//获取使用ViewInjector注解的所有元素
Set<? extends Element> elementSet = roundEnv.getElementsAnnotatedWith(ViewInjector);
for(Element element : elementSet){
//注解的字段
VariableElement varElement = (VariableElement)element;
//获取某个字段所属的类的完整路径
String className = getParentClassName(varElement);
//获取这个类上所有带有ViewInjector注解的字段
List<VariableElement> cacheElements = annotationMap.get(className);
if (cacheElements == null) {
cacheElements = new LinkedList<VariableElement>();
}
//将元素添加到该类型对应的字段列表中
cacheElements.add(varElement);
//以类的路径为key,字段列表为value,存入map
//这里是将所在字段按所属的类型进行分类
annotationMap.put(className, cacheElements);
}
}
/**
*获取某个字段所属的类的完整路径
*/
private String getParentClassName(VariableElement varElement) {
//获取该元素所在的类型,例如某个View是某个Activity的字段,这里就是获取这个Activity的类型
TypeElement typeElement = (TypeElement)varElement.getEnclosingElement();
//获取typeElement的包名
String packageName = AnnotationUtil.getPackageName(mProcessingEnv, typeElement);
//类型的完整路径名,比如某个Activity的完整路径
return packageName + "." + typeElement.getSimpleName().toString();
}
}
2、ViewInjectorProcessor.java
符合规则的类在这里处理
//指定APT工具访问规则
@SupportedAnnotationTypes("com.jasonknife.annotation.ViewInjector")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class ViewInjectorProcessor extends AbstractProcessor {
public List<AnnotationHandler> mHandlers = new ArrayList<AnnotationHandler>();
Map<String,List<VariableElement>> map = new HashMap<String,List<VariableElement>>();
AdapterWriter mWriter;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
registerHandlers();
//2.根据map生成辅助类
mWriter = new DefaultAdapterWriter(processingEnv);
}
private void registerHandlers(){
mHandlers.add(new ViewInjectHandler());
}
//符合规则的类信息,在这里处理
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
//1.roundEnv->整理出Map<String, List<VariableElement>> (key->完整类名,value->属性集合)
for(AnnotationHandler handler : mHandlers){
handler.attachProcessingEnv(processingEnv);
map.putAll(handler.handleAnnotation(roundEnv));
}
mWriter.generate(map);
return true;
}
}
3、生成辅助类的Writer:AbstractWriter.java
public abstract class AbstractWriter implements AdapterWriter {
private ProcessingEnvironment mProcessingEnv;
private Filer mFiler;
public AbstractWriter(ProcessingEnvironment env) {
this.mProcessingEnv = env;
this.mFiler = this.mProcessingEnv.getFiler();
}
@Override
public void generate(Map<String,List<VariableElement>> map) {
//模板方法
Iterator<Entry<String, List<VariableElement>>> entry = map.entrySet().iterator();
while(iterator.hasNext()){
Entry<String,List<VariableElement>> entry = iterator.next();
//属性集合
List<VariableElement> cacheElements = entry.getValue();
if(cacheElements == null || cacheElements.size() == 0) {
continue;
}
InjectInfo info = createInjectInfo(cacheElements.get(0));
//创建一个Java源文件
Writer writer = null;
try{
JavaFileObject javaFileObject = mFiler.createSourceFile(info.getFullClassName());
writer = javaFileObject.openWriter();
//头部,模板方法只控制算法的骨架,具体的交给子类实现
generateImport(writer,info);
for (VariableElement variableElement : cacheElements) {
//属性部分
writeField(writer,variableElement,info);
}
//尾部
writeEnd(writer);
}catch(IOException e){
e.printStackTrace();
}finally{
IOUtil.closeQuitly(writer);
}
}
}
private InjectInfo createInjectInfo(VariableElement variableElement) {
//属性所属的类
TypeElement typeElement = (TypeElement)variableElement.getEnclosingElement();
String packageName = AnnotationUtil.getPackageName(mProcessingEnv,variableElement);
String className = typeElement.getSimpleName().toString();
return new InjectInfo(packageName,className);
}
/**
*生成头部
*/
protected abstract void generateImport(Writer writer,InjectInfo info) throws IOException;
/**
*生成尾部
*/
protected abstract void writeField(Writer writer,VariableElement element,InjectInfo info);
/**
*产生结尾部分
*/
protected abstract void writeEnd(Writer writer) throws IOException;
/**
*注入信息
*/
class InjectInfo{
public String packageName;
public String className;
//辅助类的类名
public String newClassName;
public InjectInfo(String packageName,String className) {
this.packageName = packageName;
this.className = className ;
this.newClassName = className + JsonKnife.SUEFIX;
}
public String getFullClassName() {
return this.packageName +"." +this.newClassName;
}
}
}
4、具体生成辅助类的子类:DefaultAdapterWriter.java
public class DefaultAdapterWriter extends AbstractWriter {
public DefaultAdapterWriter(ProcessingEnvironment processingEnv) {
super(processingEnv);
}
@Override
protected void generateImport(Writer writer, InjectInfo info) throws IOException {
writer.write("package "+info.packageName +";");
writer.write("\n\n");
writer.write("import com.jasonknife.adapter.InjectAdapter;");
writer.write("\n");
writer.write("import com.jasonknife.util.ViewFinder;");
writer.write("\n\n\n");
writer.write("/*This Class is generated by JasonKnife, do not modify!*/");
writer.write("\n");
writer.write("public class "+info.newClassName+" implements InjectAdapter<"+info.);
writer.write("\n\n");
writer.write("public void injects("+info.className+" target) {");
writer.write("\n");
}
@Override
protected void writeField(Writer writer, VariableElement element, InjectInfo info) throw IOException {
ViewInjector viewInjector = element.getAnnotation(ViewInjector.class);
int id = viewInjector.value();
String fieldName = element.getSimpleName().toString();
writer.write("target."+fieldName+" = ViewFinder.findViewById(target, "+id+");");
writer.write("\n");
}
@Override
protected void writeEnd(Writer writer)throws IOException {
writer.write(" }");
writer.write("\n\n");
writer.write("}");
}
}
得到辅助类MainActivity$InjectAdapter.java
这个类里面的injects方法才是给控件赋值的真正方法
public class MainActivity$InjectAdapter implements InjectAdapter {
public void injects(MainActivity target) {
target.text = ViewFinder.findViewById(target,2131099648);
target.btn = ViewFinder.findViewById(target,2131099649);
}
}
编写注入类:
public final class JsonKnife {
public static final String SUEFIX ="$InjectAdapter";
public static void inject(Activity activity){
InjectAdapter<Activity> adapter = getViewAdapter(activity.getClass());
adapter.injects(activity);
}
/**
*获取辅助类实例
*/
private static <T> InjectAdapter<T> getViewAdapter(Class<?> clazz) {
InjectAdapter<T> adapter = null;
String adapterClsName = clazz.getName() + SUEFIX;
try{
Class<?> adapterClazz = Class.forName(adapterClsName);
adapter = adapterClazz.newInstance();
}catch(Exception e){
e.printStackTrace();
}
//NullAdapter 空对象模式
return adapter == null ? new NullAdapter : adapter;
}
}
使用方法
public class MainActivity extends Activity implements OnClickListener {
@ViewInject(R.id.text)
protected TextView text;
@ViewInject(R.id.button)
protected Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
JsonKnife.inject(this);
btn.setOnClickListener(this);
}
public void onClick(View v){
Log.d("json","按钮不为空,注入成功...");
}
}
本文介绍了一种利用Java注解处理器APT自动生成辅助类的方法,通过解析ViewInjector注解,自动生成控件注入代码,简化Activity中的视图绑定操作。
1414

被折叠的 条评论
为什么被折叠?



