@yudesong
2017-04-06T15:08:47.000000Z
字数 7952
阅读 630
Android ButterKnife
/*** Created by Zeno on 2016/10/22.** 辅助类的父接口 , T 代表注入的目标类型,ViewInject注入目标为Activity*/public interface IVInjectorAdapter<T> {void injects(T target);}
/*** Created by Zeno on 2016/10/21.** View inject* 字段注入注解,可以新建多个注解,再通过AnnotationProcessor进行注解处理* RetentionPolicy.CLASS ,在编译的时候进行注解 。我们需要在生成.class文件的时候需要进行处理*/@Retention(RetentionPolicy.CLASS)@Target(ElementType.FIELD)public @interface VInjector {int value();}
/*** Created by Zeno on 2016/10/21.** Inject in View annotation processor** 需要在配置文件中指定处理类 resources/META-INF/services/javax.annotation.processing.Processor* com.zeno.viewinject.apt.VInjectProcessor*/@SupportedAnnotationTypes("com.zeno.viewinject.annotation.VInjector")@SupportedSourceVersion(SourceVersion.RELEASE_6)public class VInjectProcessor extends AbstractProcessor {List<IAnnotationHandler> mAnnotationHandler = new ArrayList<>();Map<String,List<VariableElement>> mHandleAnnotationMap = new HashMap<>();private IGenerateAdapter mGenerateAdapter;@Overridepublic synchronized void init(ProcessingEnvironment processingEnv) {super.init(processingEnv);// init annotation handler , add handlerregisterHandler(new VInjectHandler());// init generate adaptermGenerateAdapter = new ViewGenerateAdapter(processingEnv);}/*可以有多个处理*/protected void registerHandler(IAnnotationHandler handler) {mAnnotationHandler.add(handler);}// annotation into process run@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {for (IAnnotationHandler handler : mAnnotationHandler) {// attach environment , 关联环境handler.attachProcessingEnvironment(processingEnv);// handle annotation 处理注解 ,得到注解类的属性列表mHandleAnnotationMap.putAll(handler.handleAnnotation(roundEnv));}// 生成辅助类mGenerateAdapter.generate(mHandleAnnotationMap);// 表示处理return true;}}
public abstract class AbstractGenerateAdapter implements IGenerateAdapter {private ProcessingEnvironment processingEnvironment;private final Filer mFiler;public AbstractGenerateAdapter(ProcessingEnvironment processingEnvironment) {this.processingEnvironment = processingEnvironment;mFiler = processingEnvironment.getFiler();}/*** 模版方法 : 确定算法的框架 ,将算法的实现推迟到子类里面* @param map*/@Overridepublic void generate(Map<String, List<VariableElement>> map) {Set<Map.Entry<String, List<VariableElement>>> entries = map.entrySet();Iterator<Map.Entry<String, List<VariableElement>>> iterator = entries.iterator();PrintUtils.print("size === "+entries.size());// 遍历出注入的属性集合while (iterator.hasNext()){Map.Entry<String, List<VariableElement>> entry = iterator.next();List<VariableElement> elementList = entry.getValue();if (elementList == null || elementList.isEmpty()) {continue;}InjectInfo injectInfo = createInjectInfo(elementList.get(0));/*创建一个Java源文件*/Writer writer = null;try {JavaFileObject javaFileObject = mFiler.createSourceFile(injectInfo.getFullClassName());writer = javaFileObject.openWriter();/*头部*/generateImport(writer,injectInfo);/*属性部分*/for(VariableElement element : elementList) {generateField(writer,element,injectInfo);}PrintUtils.print("\n\n what is one ?....\n\n");/*尾部*/generateFooter(writer);} catch (IOException e) {e.printStackTrace();}finally {if (writer != null) {try {writer.close();} catch (IOException e) {e.printStackTrace();}}}}}/*** 创建一个InjectInfo对象* @param variableElement* @return*/private InjectInfo createInjectInfo(VariableElement variableElement) {TypeElement typeElement = (TypeElement) variableElement.getEnclosingElement();String className = typeElement.getSimpleName().toString();String packageName = AnnotationUtils.getPackageName(processingEnvironment, typeElement);return new InjectInfo(packageName,className);}/*** 生成import 头部* @param writer*/protected abstract void generateImport(Writer writer,InjectInfo injectInfo) throws IOException;/*** 生成类字段* @param writer*/protected abstract void generateField(Writer writer,VariableElement variableElement,InjectInfo injectInfo) throws IOException;/*** 生成尾部* @param writer*/protected abstract void generateFooter(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+ ViewInject.SUFFIX;}/*** 辅助类的完整类名* @return string className*/public String getFullClassName(){return packageName+"."+newClassName;}}}
public interface IGenerateAdapter {/*** 根据解析注解的内容生成辅助类* @param map*/void generate(Map<String,List<VariableElement>> map);}
public class ViewGenerateAdapter extends AbstractGenerateAdapter {public ViewGenerateAdapter(ProcessingEnvironment processingEnvironment) {super(processingEnvironment);}@Overrideprotected void generateImport(Writer writer, InjectInfo injectInfo) throws IOException {writer.write("package "+injectInfo.packageName+";");writer.write("\n\n");writer.write("import com.zeno.viewinject.adapter.IVInjectorAdapter;");writer.write("\n\n");writer.write("import com.zeno.viewinject.utils.ViewFinder;");writer.write("\n\n\n");writer.write("/* This class file is generated by ViewInject , do not modify */");writer.write("\n");writer.write("public class "+injectInfo.newClassName+" implements IVInjectorAdapter<"+injectInfo.className+"> {");writer.write("\n\n");writer.write("public void injects("+injectInfo.className+" target) {");writer.write("\n");}@Overrideprotected void generateField(Writer writer, VariableElement variableElement, InjectInfo injectInfo) throws IOException {VInjector vInjector = variableElement.getAnnotation(VInjector.class);int resId = vInjector.value();String fieldName = variableElement.getSimpleName().toString();writer.write("\t\ttarget."+fieldName+" = ViewFinder.findViewById(target,"+resId+");");writer.write("\n");}@Overrideprotected void generateFooter(Writer writer) throws IOException {writer.write(" \t}");writer.write("\n\n");writer.write("}");}}
public interface IAnnotationHandler {/*** attch environment* @param environment 处理环境*/void attachProcessingEnvironment(ProcessingEnvironment environment) ;/*** handle annotation 处理注解 ,生成辅助类的时候需要用到注解的类型* @param roundEnvironment 周边环境* @return <p>* Map<String,List<VariableElement>>* key ---> 表示是哪个类的注入 (宿主)* value ---> 表示注解类的注入的字段属性列表 (注解字段)* </p>*/Map<java.lang.String, List<VariableElement>> handleAnnotation(RoundEnvironment roundEnvironment);}
public class VInjectHandler implements IAnnotationHandler {private ProcessingEnvironment mProcessingEnvironment;@Overridepublic void attachProcessingEnvironment(ProcessingEnvironment environment) {this.mProcessingEnvironment = environment;}@Overridepublic Map<String, List<VariableElement>> handleAnnotation(RoundEnvironment roundEnvironment) {Map<String,List<VariableElement>> map = new HashMap<>();/*获取一个类中带有VInjector注解的属性列表*/Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(VInjector.class);for (Element element : elements) {VariableElement variableElement = (VariableElement) element;/*获取类名 ,将类目与属性配对,一个类,对于他的属性列表*/String className = getFullClassName(variableElement);List<VariableElement> cacheElements = map.get(className);if (cacheElements == null) {cacheElements = new ArrayList<>();map.put(className,cacheElements);}cacheElements.add(variableElement);}return map;}/*** 获取注解属性的完整类名* @param variableElement*/private String getFullClassName(VariableElement variableElement) {TypeElement typeElement = (TypeElement) variableElement.getEnclosingElement();String packageName = AnnotationUtils.getPackageName(mProcessingEnvironment,typeElement);return packageName+"."+typeElement.getSimpleName().toString();}}
public class ViewInject {public static final String SUFFIX = "$VInjectorAdapter";static Map<Class<? extends Activity>,IVInjectorAdapter<?>> mInjectorAdapter = new HashMap();public static void inject(Activity activity) {IVInjectorAdapter<Object> vInjectorAdapter = getVInjectorAdapter(activity.getClass());vInjectorAdapter.injects(activity);}private static <T>IVInjectorAdapter<T> getVInjectorAdapter(Class<? extends Activity> clazz){IVInjectorAdapter<T> injectorAdapter = (IVInjectorAdapter<T>) mInjectorAdapter.get(clazz);if (injectorAdapter != null){return injectorAdapter;}String adapterClassName = clazz.getName()+SUFFIX;try{injectorAdapter = (IVInjectorAdapter<T>) Class.forName(adapterClassName).newInstance();mInjectorAdapter.put(clazz,injectorAdapter);}catch (Exception e){e.printStackTrace();}return injectorAdapter;}}