上一节我们已经搭建好了环境,和一个简易的demo,我们在此基础上再写一个简单的注解demo
先看一看项目结构

1,建一个注解类取名叫InjectView
@Retention(RetentionPolicy.CLASS)
public @interface InjectView {
int value();
}
2,在process Java moduel创建注解处理器ViewInjectorProcessor
在这里Google给我提供了一个依赖包,专门为了减少建立META-INF.services的步骤
在Java moduel的build中添加依赖:
compile 'com.google.auto.service:auto-service:1.0-rc2'
这个类就这样写:
@AutoService(Processor.class)
public class ViewInjectorProcessor extends AbstractProcessor {
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public Set<String> getSupportedAnnotationTypes() {
return (Collections.singleton(InjectView.class.getCanonicalName()));
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
return false;
}
}
3,建立注解处理接口类AnnotationHandler
public interface AnnotationHandler {
/**
* @param processingEnv
*/
void attachProcessingEnv(ProcessingEnvironment processingEnv);
/**
* @param roundEnv
* @return
*/
Map<String, List<VariableElement>> handleAnnotation(RoundEnvironment roundEnv);
// Map<String, InjectorInfo> handleAnnotation(RoundEnvironment roundEnv);
}
ViewInjectHandler实现里面的方法
public class ViewInjectHandler implements com.example.annote.handler.AnnotationHandler {
ProcessingEnvironment mProcessingEnv;
private Map<String, InjectorInfo> mInfoMap = new HashMap<>();
@Override
public void attachProcessingEnv(ProcessingEnvironment processingEnv) {
mProcessingEnv = processingEnv;
}
@Override
public Map<String, List<VariableElement>> handleAnnotation(RoundEnvironment roundEnv) {
// public Map<String, InjectorInfo> handleAnnotation(RoundEnvironment roundEnv) {
Map<String, List<VariableElement>> annotationMap = new HashMap<String, List<VariableElement>>();
// 获取使用ViewInjector注解的所有元素
Set<? extends Element> elementSet = roundEnv.getElementsAnnotatedWith(InjectView.class);
for (Element element : elementSet) {
// 注解的字段
VariableElement varElement = (VariableElement) element;
// 类型的完整路径名,比如某个Activity的完整路径
String className = AnnotationUtil.getParentClassName(mProcessingEnv,varElement);
// 获取这个类型的所有注解,例如某个Activity中的所有View的注解对象
List<VariableElement> cacheElements = annotationMap.get(className);
if (cacheElements == null) {
cacheElements = new LinkedList<VariableElement>();
}
// 将元素添加到该类型对应的字段列表中
cacheElements.add(varElement);
// 以类的路径为key,字段列表为value,存入map.
// 这里是将所在字段按所属的类型进行分类
annotationMap.put(className, cacheElements);
}
return annotationMap;
}
}
4,建立接口AdapterWriter
public interface AdapterWriter {
void generate(Map<String, List<VariableElement>> typeMap);
// void generate(Map<String, InjectorInfo> mInfoMap);
}
AbsWriter实现AdapterWriter
public abstract class AbsWriter implements AdapterWriter {
ProcessingEnvironment mProcessingEnv;
Filer mFiler;
public AbsWriter(ProcessingEnvironment processingEnv) {
mProcessingEnv = processingEnv;
mFiler = processingEnv.getFiler();
}
@Override
public void generate(Map<String, List<VariableElement>> typeMap) {
// public void generate(Map<String, InjectorInfo> infoMap) {
Iterator<Map.Entry<String, List<VariableElement>>> iterator = typeMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, List<VariableElement>> entry = iterator.next();
List<VariableElement> cacheElements = entry.getValue();
if (cacheElements == null || cacheElements.size() == 0) {
continue;
}
// 取第一个元素来构造注入信息
InjectorInfo info = createInjectorInfo(cacheElements.get(0));
Writer writer = null;
JavaFileObject javaFileObject;
try {
mProcessingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, info.getClassFullPath());
javaFileObject = this.mFiler.createSourceFile(info.getClassFullPath());
writer = javaFileObject.openWriter();
// 写入package, import, class以及findViews函数等代码段
generateImport(writer, info);
// 写入该类中的所有字段到findViews方法中
for (VariableElement variableElement : entry.getValue()) {
writeField(writer, variableElement, info);
}
// 写入findViews函数的大括号以及类的大括号
writeEnd(writer);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (writer != null) {
writer.flush();
}
IOUtil.closeQuitly(writer);
} catch (IOException e) {
e.printStackTrace();
}
}
}
// writeInfo(infoMap);
}
/**
* @param element
* @return
*/
protected InjectorInfo createInjectorInfo(VariableElement element) {
TypeElement typeElement = (TypeElement) element.getEnclosingElement();
String packageName = AnnotationUtil.getPackageName(mProcessingEnv, typeElement);
String className = typeElement.getSimpleName().toString();
return new InjectorInfo(packageName, className);
}
protected abstract void generateImport(Writer writer, InjectorInfo info)
throws IOException;
protected abstract void writeField(Writer writer, VariableElement element, InjectorInfo info)
throws IOException;
protected abstract void writeEnd(Writer writer) throws IOException;
}
DefaultJavaFileWriter继承AbsWriter
public class DefaultJavaFileWriter extends AbsWriter {
public DefaultJavaFileWriter(ProcessingEnvironment processingEnv) {
super(processingEnv);
}
@Override
protected void generateImport(Writer writer, InjectorInfo info) throws IOException {
writer.write("package " + info.packageName + " ;");
writer.write("\n\n");
writer.write("import com.example.butterknife.InjectAdapter ;");
writer.write("\n");
writer.write("import com.example.butterknife.ViewFinder;");
writer.write("\n\n\n");
writer.write("/* This class is generated by Simple ViewInjector, please don't modify! */ ");
writer.write("\n");
writer.write("public class " + info.newClassName
+ " implements InjectAdapter<" + info.classlName + "> { ");
writer.write("\n");
writer.write("\n");
// 查找方法
writer.write(" public void injects(" + info.classlName
+ " target) { ");
writer.write("\n");
}
@Override
protected void writeField(Writer writer, VariableElement element, InjectorInfo info) throws IOException {
InjectView injector = element.getAnnotation(InjectView.class);
// writer.write(" ViewFinder.setContentView(target," + injector.value() + " ) ; \n");
String fieldName = element.getSimpleName().toString();
writer.write(" target." + fieldName + " = ViewFinder.findViewById(target, "
+ injector.value() + " ) ; ");
writer.write("\n");
}
@Override
protected void writeEnd(Writer writer) throws IOException {
writer.write(" }");
writer.write("\n\n");
writer.write(" } ");
}
@Override
public String generateJavaCode(InjectorInfo info) {
StringBuilder builder = new StringBuilder();
builder.append("// Generated code from HyViewInjector. Do not modify!\n");
builder.append("package ").append(info.packageName).append(";\n\n");
builder.append("import android.view.View;\n");
builder.append("import com.example.butterknife.ViewFinder;\n");
builder.append("import com.example.butterknife.InjectAdapter ;\n");
builder.append('\n');
builder.append("public class ").append(info.newClassName);
builder.append(" implements InjectAdapter<T>");
builder.append(" {\n");
generateInjectMethod(builder,info);
builder.append("\n");
builder.append("}\n");
return builder.toString();
}
}
5,ViewInjectorProcessor完整的代码如下:
@AutoService(Processor.class)
public class ViewInjectorProcessor extends AbstractProcessor {
/**
* 所有注解处理器的列表
*/
List<AnnotationHandler> mHandlers = new LinkedList<AnnotationHandler>();
/**
* 类型与字段的关联表,用于在写入Java文件时按类型来写不同的文件和字段
*/
final Map<String, List<VariableElement>> map = new HashMap<String, List<VariableElement>>();
// final Map<String, InjectorInfo> mInfoMap = new HashMap<>();
/**
*
*/
AdapterWriter mWriter;
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public Set<String> getSupportedAnnotationTypes() {
return (Collections.singleton(InjectView.class.getCanonicalName()));
}
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
registerHandlers();
this.mWriter = new DefaultJavaFileWriter(processingEnv);
}
private void registerHandlers() {
this.mHandlers.add(new ViewInjectHandler());
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
Iterator var4 = this.mHandlers.iterator();
while (var4.hasNext()) {
AnnotationHandler handler = (AnnotationHandler) var4.next();
// 关联ProcessingEnvironment
handler.attachProcessingEnv(this.processingEnv);
// 解析注解相关的信息
map.putAll(handler.handleAnnotation(roundEnv));
}
// 将解析到的数据写入到具体的类型中
this.mWriter.generate(map);
return true;
}
}
6,建立Android moduel 名字butterknife,如图

创建注册activity或者fragment的视图接口注册器
public interface InjectAdapter<T> {
void injects(T target);
}
创建转化控件的静态方法类
public class ViewFinder {
public static <T extends View> T findViewById(Activity act, int id) {
return (T) act.findViewById(id);
}
/* public static void setContentView(Activity act, int layoutId) {
act.setContentView(layoutId);
}
*/
public static <T extends View> T findViewById(View rootView, int id) {
return (T) rootView.findViewById(id);
}
public static <T extends View> T findViewById(Fragment fragment, int id) {
return findViewById(fragment.getView(), id);
}
}
绑定视图的实现类
public final class ButterView {
public static final String SUFFIX = "$ViewAdapter";
static Map<Class<?>, InjectAdapter<?>> sInjectCache = new HashMap();
public ButterView() {
}
public static void inject(Activity activity) {
InjectAdapter adapter = getViewAdapter(activity.getClass());
adapter.injects(activity);
}
public static void inject(Fragment fragment, View rootView) {
InjectAdapter adapter = getViewAdapter(fragment.getClass());
if(fuckTheFragment(fragment, rootView)) {
adapter.injects(fragment);
}
}
private static boolean fuckTheFragment(Fragment fragment, View rootView) {
try {
Class e;
for(e = fragment.getClass(); e != Object.class && !e.equals(Fragment.class); e = e.getSuperclass()) {
;
}
Field rootViewField = e.getDeclaredField("mView");
rootViewField.setAccessible(true);
rootViewField.set(fragment, rootView);
Log.e("", "### getView " + fragment.getView());
return true;
} catch (SecurityException var4) {
var4.printStackTrace();
} catch (NoSuchFieldException var5) {
var5.printStackTrace();
} catch (IllegalArgumentException var6) {
var6.printStackTrace();
} catch (IllegalAccessException var7) {
var7.printStackTrace();
}
return false;
}
public static void inject(View view) {
}
private static <T> InjectAdapter<T> getViewAdapter(Class<?> clazz) {
InjectAdapter adapter = (InjectAdapter)sInjectCache.get(clazz);
if(adapter == null) {
String adapterClassName = clazz.getName() + "$ViewAdapter";
try {
Class e = Class.forName(adapterClassName);
adapter = (InjectAdapter)e.newInstance();
sInjectCache.put(e, adapter);
} catch (ClassNotFoundException var4) {
var4.printStackTrace();
} catch (InstantiationException var5) {
var5.printStackTrace();
} catch (IllegalAccessException var6) {
var6.printStackTrace();
}
}
Log.e("", "### find adapter : " + adapter);
return (InjectAdapter)adapter;
}
}
同样的需要clean Project ,rebuild,生成Java文件
在MainActivity中验证:
public class MainActivity extends AppCompatActivity {
@InjectView(R.id.textView)
TextView mTextView;
@InjectView(R.id.textView1)
TextView mTextView1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// mTextView = (TextView) findViewById(R.id.textView);
ButterView.inject(this);
mTextView.setText("我是编译时的注解");
mTextView1.setText("我是第二个注解");
// showMessage();
}
贴出utils和模型类里面的代码
public final class AnnotationUtil {
/**
* 获取包名
* @param processingEnv
* @param element
* @return
*/
public static String getPackageName(ProcessingEnvironment processingEnv, Element element) {
return processingEnv.getElementUtils().getPackageOf(element).getQualifiedName().toString();
}
/**
* 获取某个字段的完整的路径
*
* @param varElement
* @return
*/
public static String getParentClassName(ProcessingEnvironment processingEnv,VariableElement varElement) {
// 获取该元素所在的类型,例如某个View是某个Activity的字段,这里就是获取这个Activity的类型
TypeElement typeElement = (TypeElement) varElement.getEnclosingElement();
// 获取typeElement的包名
String packageName = AnnotationUtil.getPackageName(processingEnv, typeElement);
// 类型的完整路径名,比如某个Activity的完整路径
return packageName + "." + typeElement.getSimpleName().toString();
}
}
public class InjectorInfo {
public static final String SUFFIX = "$ViewAdapter";
/**
* 被注解的类的包名
*/
public String packageName;
/**
* 被注解的类的类名
*/
public String classlName;
/**
* 要创建的InjectAdapter类的完整路径,新类的名字为被注解的类名 + "$ViewAdapter", 与被注解的类在同一个包下
*/
public String newClassName;
private TypeElement typeElement;
private int layoutId;
private Map<Integer, ViewInfo> idViewMap = new HashMap<>();
public InjectorInfo(String packageName, String classlName) {
this.packageName = packageName;
newClassName=classlName+SUFFIX;
this.classlName = classlName;
}
public TypeElement getTypeElement() {
return typeElement;
}
public void setTypeElement(TypeElement typeElement) {
this.typeElement = typeElement;
}
public int getLayoutId() {
return layoutId;
}
public void setLayoutId(int layoutId) {
this.layoutId = layoutId;
}
public void putViewInfo(int id, ViewInfo viewInfo) {
idViewMap.put(id, viewInfo);
}
public Map<Integer, ViewInfo> getIdViewMap() {
return idViewMap;
}
public String getClassFullPath(){
return packageName+ "."+newClassName;
}
}
public class ViewInfo {
private int id;
private String type;
private String name;
public ViewInfo(int id, String type, String name) {
this.id = id;
this.type = type;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
运行后如图:

这样一个简单的编译时注解框架就打造好了。
网友评论