android te 编译,Android 编译时注解实现

编译时注解:在编译的时候,通过注解处理器处理对应的注解。

1.新建一个项目,然后在新建两个Java Module(annotation和processor)和另一个android module(api)结构图如下

6253a51f770d

project.png

2.建立依赖关系和第三方库

a.在项目build.gradle里面添加apt插件

classpath >'com.neenbedankt.gradle.plugins:android-apt:1.8'

mavenCentral()

如图:

6253a51f770d

project.png

b.在app module的build.gradle里面添加

apply plugin: 'com.neenbedankt.android-apt'

和注解处理

apt project(':javaprocessor')

以及注解申明

compile project(':javaannotation')

接口调用

compile project(':api')

如图

6253a51f770d

app.png

c.在javaprocessor的build.gradle里面添加注解以及生成代码的库文件

compile 'com.google.auto:auto-common:0.8'

compile 'com.google.auto.service:auto-service:1.0-rc3'

compile 'com.squareup:javapoet:1.8.0'

compile project(':javaannotation')

如图:

6253a51f770d

javaprocessor.png

3贴出部分代码:

complier

ProxyProcessor

@AutoService(Processor.class)

public class ProxyProcessor extends AbstractProcessor {

private Filer filer;

private Elements elementUtils;

private Messager messager;

private Map mProxyClassMap = new HashMap<>();

@Override

public synchronized void init(ProcessingEnvironment processingEnv) {

super.init(processingEnv);

elementUtils = processingEnv.getElementUtils();

filer = processingEnv.getFiler();

messager = processingEnv.getMessager();

}

/**

* java version

* @return

*/

@Override

public SourceVersion getSupportedSourceVersion() {

return SourceVersion.latest();

}

/**

* deal with the annotation below

* @return

*/

@Override

public Set getSupportedAnnotationTypes() {

Set set = new HashSet<>();

set.add(BindView.class.getCanonicalName());

set.add(OnClick.class.getCanonicalName());

set.add(OnLongClick.class.getCanonicalName());

set.add(OnItemClick.class.getCanonicalName());

set.add(OnTouch.class.getCanonicalName());

set.add(OnPageChange.class.getCanonicalName());

set.add(BindStringResource.class.getCanonicalName());

return set;

}

@Override

public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {

//bindView

for (Element element : roundEnv.getElementsAnnotatedWith(BindView.class)) {

if (!isValid(BindView.class, "fields", element)) {

return true;

}

dealWithBindView(element);

}

//to build java class file

for (Map.Entry entry : mProxyClassMap.entrySet()) {

try {

entry.getValue().generteFile().writeTo(filer);

} catch (IOException e) {

e.printStackTrace();

}

}

mProxyClassMap.clear();

return true;

}

private void dealWithBindView(Element element) {

FieldViewBinding fieldViewBinding = new FieldViewBinding(element,BindView.class);

ProxyClass proxyClass = getProxyClass(element);

proxyClass.addBindView(fieldViewBinding);

}

//create proxy class

private ProxyClass getProxyClass(Element element) {

String typeElementName;

typeElementName = element.getEnclosingElement().toString();

ProxyClass proxyClass = mProxyClassMap.get(typeElementName);

if (proxyClass == null) {

proxyClass = new ProxyClass(elementUtils, element);

mProxyClassMap.put(typeElementName, proxyClass);

}

return proxyClass;

}

/**

* check is valid

* @param annotationClass

* @param targetThing

* @param element

* @return

*/

private boolean isValid(Class extends Annotation> annotationClass, String targetThing, Element element) {

boolean isVaild = true;

TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();

String qualifiedName = enclosingElement.getQualifiedName().toString();

Set modifiers = element.getModifiers();

//private or static

if (modifiers.toString().contains(Modifier.PRIVATE.name().toLowerCase()) || modifiers.toString().contains(Modifier.STATIC.name().toLowerCase())) {

messager.printMessage(Diagnostic.Kind.ERROR, String.format("@%s %s must not be private or static. (%s.%s)",

annotationClass.getSimpleName(), targetThing, enclosingElement.getQualifiedName(),

element.getSimpleName()), element);

isVaild = false;

}

// parent is not class

if (enclosingElement.getKind() != ElementKind.CLASS) {

messager.printMessage(Diagnostic.Kind.ERROR, String.format("@%s %s may only be contained in classes. (%s.%s)",

annotationClass.getSimpleName(), targetThing, enclosingElement.getQualifiedName(),

element.getSimpleName()), enclosingElement);

isVaild = false;

}

//android framework

if (qualifiedName.startsWith("android.")) {

messager.printMessage(Diagnostic.Kind.ERROR, String.format("@%s-annotated class incorrectly in Android framework package. (%s)",

annotationClass.getSimpleName(), qualifiedName), element);

isVaild = false;

}

//java framework

if (qualifiedName.startsWith("java.")) {

messager.printMessage(Diagnostic.Kind.ERROR, String.format("@%s-annotated class incorrectly in Java framework package. (%s)",

annotationClass.getSimpleName(), qualifiedName), element);

isVaild = false;

}

return isVaild;

}

}

FieldViewBinding

/**

* deal with field

*/

public class FieldViewBinding {

private VariableElement mElement;

private int mResId;

private String mVariableName;

private TypeMirror mTypeMirror;

private int getValues(Element element, Class extends Annotation> annotationCls) {

if (annotationCls.getSimpleName().equals(BindView.class.getSimpleName())) {

return element.getAnnotation(BindView.class).value();

} else if (annotationCls.getSimpleName().equals(BindStringResource.class.getSimpleName())) {

return element.getAnnotation(BindStringResource.class).value();

} else {

return -1;

}

}

public FieldViewBinding(Element element, Class extends Annotation> annotationCls) {

mElement = (VariableElement) element;

BindView bindView = element.getAnnotation(BindView.class);

mResId =getValues(element,annotationCls);

mVariableName = element.getSimpleName().toString();

mTypeMirror = element.asType();

}

public int getmResId() {

return mResId;

}

public String getmVariableName() {

return mVariableName;

}

public TypeMirror getmTypeMirror() {

return mTypeMirror;

}

public VariableElement getmElement() {

return mElement;

}

}

ProxyClass

public class ProxyClass {

private Set bindViews = new HashSet<>();

private Elements elementUtils;

private Element element;

public ProxyClass(Elements elementUtils, Element element) {

this.elementUtils = elementUtils;

this.element = element;

}

public void addBindView(FieldViewBinding fieldViewBinding) {

bindViews.add(fieldViewBinding);

}

public JavaFile generteFile() {

//activity

TypeElement typeElement = (TypeElement) element.getEnclosingElement();

//packageName

String packageName = elementUtils.getPackageOf(typeElement).getQualifiedName().toString();

//className

String className = typeElement.getQualifiedName().toString().substring(packageName.length() + 1).replace(".", "$");

//ClassName(className)

ClassName cls = ClassName.bestGuess(className);

//innerClass for T

String classNameT = typeElement.getQualifiedName().toString().substring(packageName.length() + 1).replace("$", ".");

//ClassName(classNameT)

ClassName clsT = ClassName.bestGuess(classNameT);

//class for IProxy

ClassName proxtCls = ClassName.get(Configure.PROXYPACKAGE, Configure.PROXYNAME);

//class type spec

TypeSpec.Builder typeBuilder = TypeSpec.classBuilder(className + Configure.CLASSNAME_BUFFER)

.addModifiers(Modifier.PUBLIC)

.addTypeVariable(TypeVariableName.get("T", clsT))

.addSuperinterface(ParameterizedTypeName.get(proxtCls, clsT))

// for unbind

.addField(clsT,Configure.P_NAME1,Modifier.PRIVATE)

.addField(Configure.VIEW,Configure.P_NAME2,Modifier.PRIVATE)

;

//bind method type spec

MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(Configure.BIND)

.addModifiers(Modifier.PUBLIC)

.returns(TypeName.VOID)

.addParameter(clsT, Configure.P_NAME1, Modifier.FINAL)

.addParameter(Configure.VIEW, Configure.P_NAME2, Modifier.FINAL)

//for unbind

.addStatement("this."+Configure.P_NAME1+"="+Configure.P_NAME1)

.addStatement("this."+Configure.P_NAME2+"="+Configure.P_NAME2)

.addAnnotation(Override.class);

//for unbind

MethodSpec.Builder unbind=MethodSpec.methodBuilder("unbind")

.addModifiers(Modifier.PUBLIC)

.addAnnotation(Override.class)

.returns(TypeName.VOID)

.addStatement("this."+Configure.P_NAME1+"="+Configure.NULL)

.addStatement("this."+Configure.P_NAME2+"="+Configure.NULL);

for (FieldViewBinding fieldViewBinding : bindViews) {

//target.$L=($L)root.findViewById($L);

methodBuilder.addStatement(Configure.P_NAME1 + ".$L = ($L)" + Configure.P_NAME2 + "." + Configure.FINDVIEWBYID + "($L)"

, fieldViewBinding.getmVariableName(), fieldViewBinding.getmTypeMirror(), fieldViewBinding.getmResId());

}

typeBuilder.addMethod(methodBuilder.build());

//for unbind

typeBuilder.addMethod(unbind.build());

clear();

return JavaFile.builder(packageName, typeBuilder.build())

.addFileComment("this is auto create file !")

.build();

}

private void clear() {

bindViews.clear();

}

}

annotation

BindView

@Retention(RetentionPolicy.CLASS)

@Target(ElementType.FIELD)

public @interface BindView {

int value();

}

api

Inject

public class Inject {

private static IProxy proxy;

public static void inject(Activity target) {

View view = target.getWindow().getDecorView();

inject(target, view);

}

public static void unbind() {

//for unbind

if (proxy != null)

proxy.unbind();

}

public static void inject(Object target, View root) {

String clsName = target.getClass().getName();

Log.e("========",clsName);

try {

Class proxyCls = Class.forName(clsName + "$$IProxy");

proxy = (IProxy) proxyCls.newInstance();

proxy.bind(target, root);

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (InstantiationException e) {

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

}

IProxy

public interface IProxy {

void bind(T target,View root);

void unbind();

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值