Android注解笔记
2019-08-07 本文已影响0人
R7_Perfect
注解(Annotation)
元注解
@Target 表明我们注解可以出现的地方。是一个ElementType枚举
类型 | 说明 |
---|---|
ElementType.TYPE | 接口、类、枚举、注解 |
ElementType.FIELD | 字段、枚举的常量 |
ElementType.METHOD | 方法 |
ElementType.PARAMETER | 方法参数 |
ElementType.CONSTRUCTOR | 构造函数 |
ElementType.LOCAL_VARIABLE | 局部变量 |
ElementType.ANNOTATION_TYPE | 注解 |
ElementType.PACKAGE | 包 |
@Retention 这个注解的的存活时间
类型 | 说明 |
---|---|
RetentionPolicy.SOURCE | 注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃 |
RetentionPolicy.CLASS | 注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期 |
RetentionPolicy.RUNTIME | 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在 |
@Document 表明注解可以被javadoc此类的工具文档化
@Inherited 是否允许子类继承该注解,默认为false
反射相关
/**
* 包名加类名
*/
public String getName();
/**
* 类名
*/
public String getSimpleName();
/**
* 返回当前类和父类层次的public构造方法
*/
public Constructor<?>[] getConstructors();
/**
* 返回当前类所有的构造方法(public、private和protected)
* 不包括父类
*/
public Constructor<?>[] getDeclaredConstructors();
/**
* 返回当前类所有public的字段,包括父类
*/
public Field[] getFields();
/**
* 返回当前类所有申明的字段,即包括public、private和protected,
* 不包括父类
*/
public native Field[] getDeclaredFields();
/**
* 返回当前类所有public的方法,包括父类
*/
public Method[] getMethods();
/**
* 返回当前类所有的方法,即包括public、private和protected,
* 不包括父类
*/
public Method[] getDeclaredMethods();
/**
* 获取局部或匿名内部类在定义时所在的方法
*/
public Method getEnclosingMethod();
/**
* 获取当前类的包
*/
public Package getPackage();
/**
* 获取当前类的包名
*/
public String getPackageName$();
/**
* 获取当前类的直接超类的 Type
*/
public Type getGenericSuperclass();
/**
* 返回当前类直接实现的接口.不包含泛型参数信息
*/
public Class<?>[] getInterfaces();
/**
* 返回当前类的修饰符,public,private,protected
*/
public int getModifiers();
//==========================注解相关===========================================
/**
* 指定类型的注释是否存在于此元素上
*/
default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
return getAnnotation(annotationClass) != null;
}
/**
* 返回该元素上存在的指定类型的注解
*/
<T extends Annotation> T getAnnotation(Class<T> annotationClass);
/**
* 返回该元素上存在的所有注解
*/
Annotation[] getAnnotations();
/**
* 返回该元素指定类型的注解
*/
default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
return AnnotatedElements.getDirectOrIndirectAnnotationsByType(this, annotationClass);
}
/**
* 返回直接存在与该元素上的所有注释(父类里面的不算)
*/
default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
Objects.requireNonNull(annotationClass);
// Loop over all directly-present annotations looking for a matching one
for (Annotation annotation : getDeclaredAnnotations()) {
if (annotationClass.equals(annotation.annotationType())) {
// More robust to do a dynamic cast at runtime instead
// of compile-time only.
return annotationClass.cast(annotation);
}
}
return null;
}
/**
* 返回直接存在该元素岸上某类型的注释
*/
default <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
return AnnotatedElements.getDirectOrIndirectAnnotationsByType(this, annotationClass);
}
/**
* 返回直接存在与该元素上的所有注释
*/
Annotation[] getDeclaredAnnotations();
运行时注解
ButterKnife例子:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface BindView {
int value();
}
public class ButterKnifeProcess {
/**
* 绑定Activity
*/
public static void bind(final Activity activity) {
Class annotationParent = activity.getClass();
Field[] fields = annotationParent.getDeclaredFields();
Method[] methods = annotationParent.getDeclaredMethods();
// OnClick
// 找到类里面所有的方法
for (final Method method : methods) {
//找到添加了OnClick注解的方法
OnClick clickMethod = method.getAnnotation(OnClick.class);
if (clickMethod != null && clickMethod.value().length != 0) {
for (int id : clickMethod.value()) {
final View view = activity.findViewById(id);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
method.invoke(activity, view);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
});
}
}
}
}
}
public class MainActivity extends AppCompatActivity {
//自动绑定view
@BindView(R.id.text_abstract_processor)
TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnifeProcess.bind(this);
}
}
编译时注解
注解处理器类
/**
* 每个Annotation Processor必须有一个空的构造函数。
* 编译期间,init()会自动被注解处理工具调用,并传入ProcessingEnvironment参数,
* 通过该参数可以获取到很多有用的工具类(Element,Filer,Messager等)
*/
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
}
/**
* 用于指定自定义注解处理器(Annotation Processor)是注册给哪些注解的(Annotation),
* 注解(Annotation)指定必须是完整的包名+类名
*/
@Override
public Set<String> getSupportedAnnotationTypes() {
return super.getSupportedAnnotationTypes();
}
/**
* 用于指定你的java版本,一般返回:SourceVersion.latestSupported()
*/
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
/**
* Annotation Processor扫描出的结果会存储进roundEnvironment中,可以在这里获取到注解内容,编写你的操作逻辑。
* 注意:process()函数中不能直接进行异常抛出,否则程序会异常崩溃
*/
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
return false;
}
Element子类 | 解释 |
---|---|
TypeElement | 类或接口元素 |
VariableElement | 字段、enum常量、方法或构造方法参数、局部变量或异常参数元素 |
ExecutableElement | 类或接口的方法、构造方法,或者注解类型元素 |
PackageElement | 包元素 |
TypeParameterElement | 类、接口、方法或构造方法元素的泛型参数 |
/**
* 返回此元素定义的类型,int,long这些
*/
TypeMirror asType();
/**
* 返回此元素的种类:包、类、接口、方法、字段
*/
ElementKind getKind();
/**
* 返回此元素的修饰符:public、private、protected
*/
Set<Modifier> getModifiers();
/**
* 返回此元素的简单名称(类名)
*/
Name getSimpleName();
/**
* 返回封装此元素的最里层元素。
* 如果此元素的声明在词法上直接封装在另一个元素的声明中,则返回那个封装元素;
* 如果此元素是顶层类型,则返回它的包;
* 如果此元素是一个包,则返回 null;
* 如果此元素是一个泛型参数,则返回 null.
*/
Element getEnclosingElement();
/**
* 返回此元素直接封装的子元素
*/
List<? extends Element> getEnclosedElements();
/**
* 返回直接存在于此元素上的注解
* 要获得继承的注解,可使用 getAllAnnotationMirrors
*/
List<? extends AnnotationMirror> getAnnotationMirrors();
/**
* 返回此元素上存在的指定类型的注解
*/
<A extends Annotation> A getAnnotation(Class<A> var1);
注解解析器帮助类 | 解释 |
---|---|
Elements | 一个用来处理Element的工具类 |
Types | 一个用来处理TypeMirror的工具类 |
Filer | 用于创建文件(比如创建class文件) |
Messager | 用于输出,类似printf函数 |
实例
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
public @interface JsBridgeMethod {
String value() default "";
}
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface JsBridgeApi {
String value() default "";
}
@AutoService(Processor.class)
public class JsBridgeAnnoProcessor extends AbstractProcessor {
private Elements mElementUtils; //基于元素进行操作的工具方法
private Filer mFileCreator; //代码创建者
private Messager mMessager; //日志,提示者,提示错误、警告
private Map<String, HashMap<String, String>> exposedMethodsByName = new HashMap<>();//做缓存用
private Map<String, String> classNameByJsApiName = new HashMap<>();//类名存储
private String packageName;
@Override
public synchronized void init(final ProcessingEnvironment processingEnv) {
super.init(processingEnv);
mElementUtils = processingEnv.getElementUtils();
mFileCreator = processingEnv.getFiler();
mMessager = processingEnv.getMessager();
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> types = new LinkedHashSet<>();
types.add(JsBridgeMethod.class.getCanonicalName());
return types;
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
final Set<? extends Element> elementsAnnotatedWith =
roundEnvironment.getElementsAnnotatedWith(JsBridgeMethod.class);
for (Element element : elementsAnnotatedWith) {
ExecutableElement executableElement = (ExecutableElement) element;
final TypeElement typeElement = (TypeElement) executableElement.getEnclosingElement();
final String s = mElementUtils.getPackageOf(typeElement).getQualifiedName().toString();
mMessager.printMessage(Diagnostic.Kind.NOTE, "package===>" + s);
if (!s.equals(packageName)) {
packageName = s;
}
final JsBridgeApi jsBridgeApi = typeElement.getAnnotation(JsBridgeApi.class);
if (jsBridgeApi != null) {
String jsBridgeApiName = jsBridgeApi.value();
if ("".equals(jsBridgeApiName)) {
jsBridgeApiName = typeElement.getSimpleName().toString();
}
//完整类名
final String qualifiedName = typeElement.getQualifiedName().toString();
JsBridgeMethod jsBridgeMethod =
executableElement.getAnnotation(JsBridgeMethod.class);
//注解上的js方法名
String jsMethodName = jsBridgeMethod.value();
//真实方法名
final String methodName = executableElement.getSimpleName().toString();
if ("".equals(jsMethodName)) {
jsMethodName = methodName;
}
classNameByJsApiName.put(jsBridgeApiName, qualifiedName);
//查询缓存中有无存过这个类
HashMap<String, String> methodsByApi;
if (!exposedMethodsByName.containsKey(jsBridgeApiName)) {
methodsByApi = new HashMap<>();
exposedMethodsByName.put(jsBridgeApiName, methodsByApi);
} else {
methodsByApi = exposedMethodsByName.get(jsBridgeApiName);
}
methodsByApi.put(jsMethodName, methodName);
}
}
writeJava();
return true;
}
private void writeJava() {
final ParameterizedTypeName hashMapType =
ParameterizedTypeName.get(ClassName.get(HashMap.class), ClassName.get(String.class),
ClassName.get(Method.class));
final MethodSpec.Builder methodBuild = MethodSpec.methodBuilder("register")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(void.class)
.addParameter(ParameterizedTypeName.get(ClassName.get(Map.class),
ClassName.get(String.class), hashMapType), "exposedMethods");
final CodeBlock.Builder codeBuilder = CodeBlock.builder();
for (String jsApiName : exposedMethodsByName.keySet()) {
String className = classNameByJsApiName.get(jsApiName);
//分割 dot 需要转义
final String[] split = className.split("\\.");
String simpleName = split[split.length - 1];
String methodMapName = "mMethodsMap" + simpleName;
codeBuilder.add("HashMap<String, Method> $L = new HashMap<>();\n", methodMapName);
final HashMap<String, String> methodNameByJsName = exposedMethodsByName.get(jsApiName);
for (String jsName : methodNameByJsName.keySet()) {
codeBuilder.add(methodMapName
+ ".put($S,$L.class.getMethod($S,com.sample.jsbridgelibrary.webView.WebViewFragmentWrapper.class,String.class,com.sample.jsbridgelibrary.bridge.Callback.class));\n",
jsName, className, methodNameByJsName.get(jsName));
}
codeBuilder.add("exposedMethods.put($S,$L);\n", jsApiName, methodMapName);
}
final MethodSpec registerMethod = methodBuild.beginControlFlow("try")
.addStatement(codeBuilder.build())
.nextControlFlow("catch ($T e)", Exception.class)
.addStatement("e.printStackTrace()")
.endControlFlow()
.build();
TypeSpec JsBridgeRegister = TypeSpec.classBuilder("JsBridgeRegister")
.addModifiers(Modifier.PUBLIC)
.addMethod(registerMethod)
.build();
mMessager.printMessage(Diagnostic.Kind.NOTE, "javaFile package===>" + packageName);
JavaFile javaFile = JavaFile.builder(packageName, JsBridgeRegister).build();
// mMessager.printMessage(Diagnostic.Kind.NOTE, javaFile.toString());
try {
javaFile.writeTo(mFileCreator);
} catch (IOException e) {
e.printStackTrace();
}
}
}