注解有三种级别,注解的保留级别不同,对注解的使用场景自然不同,
源码级别: 1.APT 在编译期能够获取注解与注解声明的类,包括类中的 所有成员信息,一般用于生成额外的辅助类.
2.可以提供IDE语法检查,取代枚举的使用
字节码: 1.在编译出Class后,通过修改Class数据以实现修改代码逻辑目的。
2.对于是否需要修改的区分或者修改为不同逻辑的判断可以使用注解(这块还没用应用实例)
运行期: 在程序运行期间,通过反射技术动态获取注解与其元素,从而完成不同的逻辑判断 应用场景(自动注入一个View的findViewById操作)
下面介绍:源码级别提供IDE语法检查案例:
public enum Teacher {
LIGUOJING,ZHUPENG
}
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {1,2})//提供语法检查需要传递的值
public @interface Teacher2 {
}
public class IdeTest {
/*
* 我们定义的test方法,只能传递 LIGUOJING 和 ZHUPENG其中一个,为了进行内存优化
* 我们现在不使用枚举,则定义方法为:
* */
private static final int LIGUOJING = 1;
private static final int ZHUPENG = 2;
// 然而此时,调用test2方法由于采用基本数据类型int,将无法进行类型限定。
// 此时使用@IntDef增加自定义注解:
public void test2(int t){
test3(LIGUOJING);
test3(ZHUPENG);
test3(3);//IDE 提供语法检查,3 不符合语法规范,但是编译运行还是没有问题
}
// test3方法提供了语法检查,传递的int值必须是@Teacher2里面定义的
public void test3(@Teacher2 int t){
}
public void test(Teacher teacher){
}
}
在程序运行期间,通过反射技术动态获取注解,并自动完成findViewById操作和成员变量的赋值
public class MainActivity extends AppCompatActivity {
@Inject(resId = R.id.tvText)
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InjectUtils.injectViewId(this);
textView.setText("通过注解进行findViewById操作");
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, MainActivity2.class);
// 这些传递的值,需要在MainActivity2中,通过注解进行赋值操作
intent.putExtra("zhupeng", "失恋好了吗");
intent.putExtra("userId", 110);
intent.putExtra("user", new User("李国菁", 29));
intent.putExtra("userArray",new User[]{new User("李菁",31),new User("李国伟",22)});
startActivity(intent);
}
});
}
}
Inject 和 Autowired注解类代码
@Target(ElementType.FIELD)//作用在成员变量上
@Retention(RetentionPolicy.RUNTIME)// 保留在运行时期
public @interface Inject {
@IdRes int resId();// 其中IdRes 的意思是:必须指定这个int 值为 R.id.xx 类型
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {
String value() default "";
}
Javabean类
public class User implements Parcelable {
private String name;
private int age;
public User(String name,int age){
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
protected User(Parcel in) {
name = in.readString();
age = in.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
跳转后MainActivity2赋值
public class MainActivity2 extends AppCompatActivity {
@Inject(resId = R.id.tvText)
private TextView textView;
@Autowired(value = "zhupeng")
private String zhupeng;
@Autowired
private int userId;
@Autowired
private User user;
@Autowired
private User[] userArray;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
InjectUtils.injectViewId(this);
InjectUtils.injectAutowired(this);
// InjectUtils.injectIntentValue(this); 这个方法只能赋值String 和int值
String str = "";
for (int i = 0; i <userArray.length ; i++) {
str+= userArray[i];
}
textView.setText(zhupeng + userId + user + "\n" + str);
}
}
InjectUtils 这块是重点内容,需要仔细查看
public class InjectUtils {
public static void injectViewId(Activity activity) {
if (activity == null) {
throw new RuntimeException("Activity is not null");
}
Class<? extends Activity> clazz = activity.getClass();
//获取所有的成员变量,包括 private类型的成员变量
Field[] allFields = clazz.getDeclaredFields();
for (Field field : allFields) {
// 判断该字段上面是否有注解
boolean isPresent = field.isAnnotationPresent(Inject.class);
if (isPresent) {
// 获取字段上的注解
Inject fieldAnnotation = field.getAnnotation(Inject.class);
int viewId = fieldAnnotation.resId();
View view = activity.findViewById(viewId);
// 修改 private 成员变量的值,必须加上下面这句,否则会有问题
field.setAccessible(true);
// 给这个字段进行赋值
try {
field.set(activity, view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
public static void injectIntentValue(Activity activity) {
if (activity == null) {
throw new RuntimeException("Activity is not null");
}
Class<? extends Activity> clazz = activity.getClass();
//获取所有的成员变量,包括 private类型的成员变量
Field[] allFields = clazz.getDeclaredFields();
for (Field field : allFields) {
// 判断该字段上面是否有注解
boolean isPresent = field.isAnnotationPresent(Autowired.class);
if (isPresent) {
// 获取字段上的注解
Autowired fieldAnnotation = field.getAnnotation(Autowired.class);
String key = TextUtils.isEmpty(fieldAnnotation.value()) ? field.getName() : fieldAnnotation.value();
try {
Object value = getValue(field.getType(), activity, key);
field.setAccessible(true);
field.set(activity, value);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
public static Object getValue(Class clazz,Activity activity,String key){
System.out.println("clazz : " + clazz);
if (clazz == String.class){
return activity.getIntent().getStringExtra(key);
}else if (clazz == int.class){
return activity.getIntent().getIntExtra(key,0);
}
return new Object();
}
public static void injectAutowired(Activity activity) {
if (activity == null) {
return;
}
Intent intent = activity.getIntent();
if (intent == null) {
return;
}
// intent 传递参数,都是把参数封装在 bundle里面进行传输的
Bundle bundle = intent.getExtras();
if (bundle == null) {
return;
}
Class<? extends Activity> clazz = activity.getClass();
// 获取所有的成员变量
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
// 判断成员变量上有没有Autowired的注解
if (field.isAnnotationPresent(Autowired.class)) {
Autowired autowired = field.getAnnotation(Autowired.class);
String key = TextUtils.isEmpty(autowired.value()) ? field.getName() : autowired.value();
// 获取key 值对应的 value
Object obj = bundle.get(key);
field.setAccessible(true);
try {
/*
* 对于数组类型实现 Parcelable 接口的需要单独处理
* */
// 获取该字段的真正类型
Class<?> type = field.getType();
System.out.println("lgj type :" + type);
// 获取数组单个元素类型
Class<?> componentType = type.getComponentType();
// type 类型是数组,并且是 Parcelable 子类数组
if (type.isArray() && Parcelable.class.isAssignableFrom(componentType)){
Object[] objs = (Object[]) obj;
Object[] objects = Arrays.copyOf(objs, objs.length, (Class<? extends Object[]>) type);
obj = objects;
}
// 通过反射进行赋值运算
field.set(activity, obj);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
通过注解然后执行一个控件的OnClick事件
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@EventType(listenerSetter = "setOnClickListener", listenerType = View.OnClickListener.class)
public @interface Click {
@IdRes int[] value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface EventType {
String listenerSetter();
Class listenerType();
}
public class MainActivity3 extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
ClickUtils.injectEvent(this);
}
@Click({R.id.tv,R.id.tv2})
public void test(View view){
Toast.makeText(this,"通过注解,来执行onClick事件",Toast.LENGTH_SHORT).show();
}
}
重点代码
public class ClickUtils {
public static void injectOnClick(final Activity activity) {
Class<? extends Activity> clazz = activity.getClass();
Method[] declaredMethods = clazz.getDeclaredMethods();
for (final Method declaredMethod : declaredMethods) {
boolean isPresent = declaredMethod.isAnnotationPresent(Click.class);
if (isPresent) {
Click annotation = declaredMethod.getAnnotation(Click.class);
int[] value = annotation.value();
for (int i = 0; i < value.length; i++) {
// 找到这个view
View view = activity.findViewById(value[i]);
// 然后设置点击事件,通过反射调用,对应的方法
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
declaredMethod.invoke(activity, v);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
});
}
}
}
}
// 自己在这瞎捉摸写的
public static void injectOnClickProxy(final Activity activity) {
Class<? extends Activity> clazz = activity.getClass();
Method[] declaredMethods = clazz.getDeclaredMethods();
for (final Method declaredMethod : declaredMethods) {
boolean isPresent = declaredMethod.isAnnotationPresent(Click.class);
if (isPresent) {
Click annotation = declaredMethod.getAnnotation(Click.class);
int[] value = annotation.value();
for (int i = 0; i < value.length; i++) {
final View view = activity.findViewById(value[i]);
try {
final Method viewClick = view.getClass().getDeclaredMethod("setOnClickListener", View.class);
// viewClick.invoke(view,view);
Object obj = Proxy.newProxyInstance(ClickUtils.class.getClassLoader(), new Class[]{View.OnClickListener.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return viewClick.invoke(view, args);
}
});
System.out.println("lgj obj :" + obj);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
public static void injectEvent(final Activity activity) {
Class<? extends Activity> clazz = activity.getClass();
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
// 获取方法上的所有注解
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
//System.out: lgj annotation:@com.lgj.xxkt.动态代理.Click(value=[2131165423, 2131165424])
System.out.println("lgj annotation:" + annotation);
//注解类型
Class<? extends Annotation> annotationType = annotation.annotationType();
// lgj annotationType:interface com.lgj.xxkt.动态代理.Click
System.out.println("lgj annotationType:" + annotationType);
if (annotationType.isAnnotationPresent(EventType.class)) {
EventType eventType = annotationType.getAnnotation(EventType.class);
//setOnClickListener
String setOnClickListener = eventType.listenerSetter();
// OnClickListener.class
Class listenerType = eventType.listenerType();
// 获取 方法上注入view 的ID
Click annotationClick = (Click) annotation;
int[] viewIds = annotationClick.value();
method.setAccessible(true);
// 需要对Activity进行代理
MyInvocationHandler<Activity> handler = new MyInvocationHandler<>(activity, method);
Object listenerProxy = Proxy.newProxyInstance(listenerType.getClassLoader(),
new Class[]{listenerType}, handler);
// System.out.println("listenerProxy : " + listenerProxy);
for (int i = 0; i < viewIds.length; i++) {
// 获取当前Activity的view (赋值)
View view = activity.findViewById(viewIds[i]);
try {
// 获取指定的方法 getDeclaredMethod 和 getMethod 的区别
// getDeclaredMethod 可以拿反射类中的公共方法 私有方法 保护方法 但不能获取继承的方法
// getMethod 可以拿到反射类及其父类中的所有公共方法
Method setter = view.getClass().getMethod(setOnClickListener, listenerType);
// 执行方法
setter.invoke(view,listenerProxy);//执行setOnclickListener里面的回调 onclick方法
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
static class MyInvocationHandler<T> implements InvocationHandler {
private Method method;
private T target;
public MyInvocationHandler(T target, Method method) {
this.target = target;
this.method = method;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return this.method.invoke(target, args);
}
}
}