注解(annotation)
元注解: 注解上的注解
注解使用场景:
retention设置不同保留时间级别:
SOURCE:源码级别,语法检查,APT,常见框架
CLASS: 字节码,AOP
RUNTIME: 和反射结合
反射(reflect)
使用注解和反射实现findViewById
1. 创建注解:
// 设置作用域为变量
@Target(ElementType.FIELD)
// 设置保留级别为运行时
@Retention(RetentionPolicy.RUNTIME)
public @interface GetView {
// 默认value(),如果有其他变量设置,比如id,则在使用的时候要用@GetView(id = "xxx")
int value();
}
2. 反射得到view并设置给对象变量
public static void getViewById(Activity activity) {
Class<? extends Activity> obj = activity.getClass();
Field[] fields = obj.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
if (fields[i].isAnnotationPresent(GetView.class)) {
GetView annotation = fields[i].getAnnotation(GetView.class);
fields[i].setAccessible(true);
try {
// set第一个参数为变量所属的对象,如果是静态变量,则传null
fields[i].set(activity, activity.findViewById(annotation.value()));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
3. 在activity中使用
@GetView(R.id.tv_go_flutter)
TextView tvFlutter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
UIUtils.getViewById(this);
}
反射中获取属性和方法加declared表明获取类内部的,不加declared表明获取类和父类的属性和方法
静态代理的步骤:
1. 创建代理类和被代理类公共的接口类
2. 被代理类实现该接口
3. 代理类实现该接口,并将代理类传入,代理类持有被代理类
动态代理创建步骤:
前两步同动态代理
创建Dynamic类实现invocationHandler接口,实现invoke方法,通过构造方法传入Object持有被代理类
通过代理生成代理接口对象,调用接口中的方法
public static void main(String[] args) {
Buyer buyer = new Buyer();
DynamicProxy dynamicProxy = new DynamicProxy(buyer);
ClassLoader classLoader = buyer.getClass().getClassLoader();
IHouse agency = (IHouse) Proxy.newProxyInstance(classLoader, new Class[]{IHouse.class}, dynamicProxy);
agency.buyHouse();
agency.renderHouse();
}
使用注解、反射和代理实现OnClick注入
Activity中使用:
@ClickView(R.id.tv_go_flutter)
public void clickGoFlutter(View view) {
Toast.makeText(MainActivity.this, "跳转flutter", Toast.LENGTH_SHORT).show();
}
首先定义注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ClickView {
int[] value();
}
实现:
public static void injectClick(final Activity activity) {
Class<? extends Activity> obj = activity.getClass();
Method[] methods = obj.getDeclaredMethods();
for (final Method method : methods) {
if (method.isAnnotationPresent(ClickView.class)) {
ClickView annotation = method.getAnnotation(ClickView.class);
Object clickProxy = Proxy.newProxyInstance(View.OnClickListener.class.getClassLoader(), new Class[]{View.OnClickListener.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method1, Object[] args) throws Throwable {
// 执行View.OnClickListener的onClick方法时转成使用注解标记的方法
return method.invoke(activity, args);
}
});
int[] ids = annotation.value();
for (int id : ids) {
View view = activity.findViewById(id);
Method clickListener;
try {
clickListener = view.getClass().getMethod("setOnClickListener", View.OnClickListener.class);
// 执行View的setOnclickListener方法,参数为代理生成的View.OnClickListener对象
clickListener.invoke(view, clickProxy);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}