一、前言
注解可以理解成标记,打标签。单独的一个注解是没用的,需要搭配使用,例如搭配反射等等。我们需要通过使用注解上的值来做相应的操作。
二、自定义一个注解
package com.example.myapplication;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义一个注解
* InjectAnnotation
* 注解可以理解成标记,打标签,
* 1、设置Retention注解,表示定义注解的级别、也可以理解为注解的生命周期
* (1)RetentionPolicy.SOURCE源码上
* 表示注解存在源码中,当通过JAVAC编译成字节码之后,注解便不存在。此类型注解可以用在我们的注解处理中
* 因为注解处理器的方法执行在编译器,我们可以在注解处理器的方法执行时候获取我们的注解内容,做相应的一些操作,例如生成一些我们需要的辅助类
* 比如Arouter框架。也可以用于源代码的检查。例如当我们的方法希望传递指定的类型的时候,可以使用注解来限制。
* (2)RetentionPolicy.CLASS字节码上
* 此类型注解表示注解在字节码中存在,即源码编译成字节码,注解一直存在。可以用在字节码增强、插装的一些实现。
* 也就是在字节码中获取注解内容,针对原有字节码进行一些修改,而达到字节码增强的效果。例如我们的热修复
* <p>
* (3)RetentionPolicy.RUNTIME 运行期间,也叫运行行注解
* 运行时注解,也就是从编译到运行,注解一直存在,在程序运行的时候,我们可以使用我们的注解。例如:我们程序运行的时候,我们可以通过获取注解+反射来实现一些功能,例如
* 实现view.findId
* <p>
* <p>
* 2、设置注解作用目标的对象
* 常用的有
* (1)TYPE 作用在类上
* (2)FIELD 变量上
* (3)METHOD 方法上
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ValueAnnotation {
String value();
DataType dataType();
}
自定义注解使用@interface关键字,并在注解上使用@Retention注解和@Target注解
- 1、设置Retention注解,表示定义注解的级别、也可以理解为注解的生命周期
(1)RetentionPolicy.SOURCE源码上
表示注解存在源码中,当通过JAVAC编译成字节码之后,注解便不存在。此类型注解可以用在我们的注解处理中
因为注解处理器的方法执行在编译器,我们可以在注解处理器的方法执行时候获取我们的注解内容,做相应的一些操作,例如生成一些我们需要的辅助类。比如Aruter框架。也可以用于源代码的检查。例如当我们的方法希望传递指定的类型的时候,可以使用注解来限制。
(2)RetentionPolicy.CLASS字节码上
此类型注解表示注解在字节码中存在,即源码编译成字节码,注解一直存在。可以用在字节码增强、插装的一些实现。 也就是在字节码中获取注解内容,针对原有字节码进行一些修改,而达到字节码增强的效果。例如我们的热修复。
(3)RetentionPolicy.RUNTIME 运行期间上的注解
也叫运行时注解,运行时注解,也就是从编译到运行,注解一直存在,在程序运行的时候,我们可以使用我们的注解。例如:我们程序运行的时候,我们可以通过获取注解+反射来实现一些功能,例如: 实现findById
- 2、设置注解作用目标的对象(Target注解)
常用的有:
(1)TYPE 作用在类上
(2)FIELD 变量上
(3)METHOD 方法上 - 3、设置注解的值
例如代码中的,value和dataType,注解值可以有多个
三、注解结合反射实现Android中Activity页面跳转Intent值的获取
1、自定义一个注解,也就是上面的注解
2、创建一个工具类
主要功能就是通过反射获取Activity中的成员属性,并且是获取带有我们自定义注解的属性成员。然后获取注解上的值,注解上设置了两个值:字符串参数名和枚举类型的数据类型。
根据数据类型和参数名,通过activity.getIntent()来获取Intent上的值,拿到值之后,给成员赋值即可
package com.example.myapplication;
import java.lang.reflect.Field;
import androidx.appcompat.app.AppCompatActivity;
public class InjectUtils {
public static void init(AppCompatActivity activity) {
//1、通过actibity对象获取class对象
Class<? extends AppCompatActivity> activityClass = activity.getClass();
//2.获取该类的所有成员
Field[] fields = activityClass.getDeclaredFields();
//3.遍历获取:有打上ValueAnnotation注解的成员
for (int i = 0; i < fields.length; i++) {
if (fields[i].isAnnotationPresent(ValueAnnotation.class)) {
try {
//4、给成员设置访问权限、
fields[i].setAccessible(true);//也就是当成员是private的时候,允许访问
//5、获取成员上的注解的值
ValueAnnotation valueAnnotations = fields[i].getAnnotation(ValueAnnotation.class);
String value = valueAnnotations.value();
DataType dataType = valueAnnotations.dataType();
//6、判断数据类型,设置值
if (dataType == DataType.IntegerData) {
Integer result = activity.getIntent().getIntExtra(value, 0);
fields[i].set(activity, result);
}
if (dataType == DataType.StringData) {
String result = activity.getIntent().getStringExtra(value);
fields[i].set(activity, result);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
在Activity上使用
package com.example.myapplication;
import android.os.Bundle;
import android.util.Log;
import java.lang.reflect.Type;
import androidx.appcompat.app.AppCompatActivity;
public class ResultActivity extends AppCompatActivity {
@ValueAnnotation(value = "result", dataType = DataType.StringData)
private String result;
@ValueAnnotation(value = "age", dataType = DataType.IntegerData)
private Integer age;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InjectUtils.init(this);
Log.e("ResultActivity", "result = " + result);
Log.e("ResultActivity", "age = " + age);
// //通过反射获取泛型类型
// //通过匿名内部类来实现,获取泛型的类型
// TypeClass<String> typeClass = new TypeClass<String>() {
// };
// Log.e("ResultActivity", "getType = "+typeClass.getType());
}
}
网友评论