butterknife架构核心

来源:互联网 发布:淘宝的等级怎么升级快 编辑:程序博客网 时间:2024/06/06 09:08

反射:

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;  }@Overridepublic 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;@Overridepublic 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);  }@Overrideprotected 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");  }@Overrideprotected 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");}@Overrideprotected 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","按钮不为空,注入成功..."); }}
原创粉丝点击