ElementType.Type | 接口、类、注解、枚举 |
ElementType.FIELD | 字段、枚举常量 |
ElementType.METHOD | 方法 |
ElementType.PARAMETER | 方法参数 |
ElementType.CONSTRUCOTOR | 构造函数 |
ElementType.LOCAL_VARIABLE | 局部变量 |
ElementType.ANNOTATION_TYPE | 注解 |
Element.PACKAGE | 包 |
RetentionPolicy.SOURCE | 源文件,当java文件被编译成class文件时,注解失效 |
RetentionPolicy.CLASS | 注解存在class 文件,当jvm 加载class文件时,注解生效,默认指定的参数 |
RetentionPolicy.RUNTIME | 注解保存到class文件,jvm加载class文件后,依然有效 |
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * author: rexkell * explain: */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface AutoCreateObject { }
2.2解析注解
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; /** * author: rexkell * explain: */ public class AutoCreateProcess { public static void bind(final Object object){ Class parentClass=object.getClass(); Field[] fields= parentClass.getFields(); for (Field field: fields){ AutoCreateObject autoCreateObject= field.getAnnotation(AutoCreateObject.class); if (autoCreateObject!=null){ field.setAccessible(true); try { Class<?> autoCreateClass= field.getType(); Constructor autoCreateConstructor= autoCreateClass.getConstructor(); field.set(object,autoCreateConstructor.newInstance()); } catch (NoSuchMethodException e) { e.printStackTrace(); }catch (IllegalAccessException e){ e.printStackTrace(); }catch (InvocationTargetException e){ e.printStackTrace(); }catch (InstantiationException e){ e.printStackTrace(); } } } } }
@AutoCreateObject
Students students;
//创建对象
AutoCreateProcess.bind(this);
3、模拟bindViewId
3.1、创建一个java Module
implementation 'com.squareup:javapoet:1.9.0' implementation 'com.google.auto.service:auto-service:1.0-rc2'
3.2 申明注解
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * author: rexkell * explain: */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.CLASS) public @interface BindView { int value() default -1; }
3.3 解析注解
import android.app.Activity; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; /** * author: rexkell * explain: */ public class MyBindView { private static Map<Class, Method> classMethodMap=new HashMap<>(); public static void bind(Activity target){ if (target!=null){ Method method = classMethodMap.get(target.getClass()); try { if (method==null){ //获取编译生成的注解类 String bindClassName= target.getPackageName()+".Bind"+target.getClass().getSimpleName(); Class bindClass=Class.forName(bindClassName); method=bindClass.getMethod("bindView",target.getClass()); classMethodMap.put(target.getClass(),method); } method.invoke(null,target); } catch (Exception e) { e.printStackTrace(); } } } }
由于是编译时产生的注解,需要通过 extends AbstractProcessor 来实现
import com.google.auto.service.AutoService; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; /** * author: rexkell * explain: */ @AutoService(Processor.class) @SupportedSourceVersion(SourceVersion.RELEASE_7) public class BindProcess extends AbstractProcessor { private Elements mElementsUtil; private Map<TypeElement,Set<Element>> mBindViewElems; @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); mElementsUtil=processingEnv.getElementUtils(); mBindViewElems=new HashMap<>(); } @Override public Set<String> getSupportedAnnotationTypes() { //添加需要解析的自定义注解类 Set<String> types=new HashSet<>(); types.add(BindView.class.getCanonicalName()); types.add(BindLayout.class.getCanonicalName()); return types; } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { System.out.println("Process start!"); initBindElems(roundEnv.getElementsAnnotatedWith(BindView.class)); generateJavaClass(); System.out.println("Process finish!"); return true; } //初始化绑定的控件 private void initBindElems(Set<? extends Element> bindElems){ for (Element bindElem : bindElems){ TypeElement enclosedElem=(TypeElement) bindElem.getEnclosingElement(); Set<Element> elems=mBindViewElems.get(enclosedElem); if (elems==null){ elems=new HashSet<>(); mBindViewElems.put(enclosedElem,elems); System.out.println(enclosedElem.getSimpleName()); } elems.add(bindElem); System.out.println("Add bind elem "+bindElem.getSimpleName()); } } private void generateJavaClass(){ //生成Bind+ClassName+.class 文件,文件内容实现findViewById for (TypeElement enclosedElem: mBindViewElems.keySet()){ MethodSpec.Builder methodSpesBuilder = MethodSpec.methodBuilder("bindView") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .addParameter(ClassName.get(enclosedElem.asType()),"activity") .returns(TypeName.VOID); BindLayout bindLayoutAnno =enclosedElem.getAnnotation(BindLayout.class); if (bindLayoutAnno!=null){ methodSpesBuilder.addStatement(String.format(Locale.US,"activity.setContentView(%d)",bindLayoutAnno.value())); } for (Element bindElem : mBindViewElems.get(enclosedElem)){ methodSpesBuilder.addStatement(String.format(Locale.US,"activity.%s=(%s)activity.findViewById(%d)", bindElem.getSimpleName(),bindElem.asType(),bindElem.getAnnotation(BindView.class).value())); } TypeSpec typeSpec=TypeSpec.classBuilder("Bind"+enclosedElem.getSimpleName()) .superclass(TypeName.get(enclosedElem.asType())) .addModifiers(Modifier.FINAL,Modifier.PUBLIC) .addMethod(methodSpesBuilder.build()) .build(); JavaFile file = JavaFile.builder(getPackageName(enclosedElem),typeSpec).build(); try { file.writeTo(processingEnv.getFiler()); } catch (IOException e) { e.printStackTrace(); } } } private String getPackageName(TypeElement typeElement){ return mElementsUtil.getPackageOf(typeElement).getQualifiedName().toString(); } }
3.4 在需要使用bindViewId 注解中引入模块。
@BindView(R.id.edt_longitude) EditText edtLongitude; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SharedPreferences sharedPreferences= this.getSharedPreferences("theme",MODE_PRIVATE); int themeId=sharedPreferences.getInt("themeId",2); if (themeId==1){ setTheme(R.style.BaseAppThemeNight); }else if (themeId==0){ setTheme(R.style.AppTheme); } setContentView(R.layout.activity_main); MyBindView.bind(this); }