动态代理+注解+反射实现View的点击事件绑定
Posted milovetingting
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态代理+注解+反射实现View的点击事件绑定相关的知识,希望对你有一定的参考价值。
个人博客
动态代理+注解+反射实现View的点击事件绑定
代理模式是给对象提供一个代理对象,由代理对象来控制原对象的引用。代理模式分为静态代理和动态代理。
静态代理
定义接口
public interface Player {
void play();
}
定义具体的实现类
public class PlayerImpl implements Player {
@Override
public void play() {
System.out.println("PlayerImpl play...");
}
}
定义代理类
public class ProxyImpl implements Player {
private Player player;
public ProxyImpl(Player player) {
this.player = player;
}
@Override
public void play() {
player.play();
}
}
可以看到,具体的实现类和代理类都会实现相同的接口类,在代理类的实现中,会引用具体的实现类。
动态代理
静态代理,在运行前定义。动态代理是在运行时创建代理和实例。JDK提供了Proxy
类来创建动态代理
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
}
先看下具体的使用
Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{Player.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(player, args);
}
});
newProxyInstance对应的三个参数:
-
类加载器
-
接口的class,Proxy会根据这个class来生成Proxy类
-
InvocationHandler,方法的回调,代理的类的方法调用时都会回调到这来
动态代理类的完整代码
public class DynamicProxy {
private Player player;
public DynamicProxy(Player player) {
this.player = player;
}
public void setPlayer(Player player) {
this.player = player;
}
public Player getProxy() {
return (Player) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{Player.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(player, args);
}
});
}
}
Proxy.newProxyInstance
方法最终是调用ProxyGenerator
的generateProxyClass
方法
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile();
if (saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
try {
int var1 = var0.lastIndexOf(46);
Path var2;
if (var1 > 0) {
Path var3 = Paths.get(var0.substring(0, var1).replace(‘.‘, File.separatorChar));
Files.createDirectories(var3);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
} else {
var2 = Paths.get(var0 + ".class");
}
Files.write(var2, var4, new OpenOption[0]);
return null;
} catch (IOException var4x) {
throw new InternalError("I/O exception saving generated file: " + var4x);
}
}
});
}
return var4;
}
动态代理生成的代理类存在于内存中。
实现点击事件的绑定
下面基于动态代理+注解+反射,实现控件的点击事件绑定。
首先定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OnClick {
@IdRes int[] value();
}
然后在Activity中定义点击事件,引用OnClick注解
@OnClick({R.id.btn1, R.id.btn2})
public void click(Button view) {
Toast.makeText(getApplicationContext(), view.getText(), Toast.LENGTH_SHORT).show();
}
在Activity中绑定
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InjectHelper.inject(this);
}
InjectHelper的实现
public static void inject(final Activity target) {
if (target == null) {
return;
}
Class<? extends Activity> clz = target.getClass();
Method[] declaredMethods = clz.getDeclaredMethods();
for (final Method method : declaredMethods) {
if (method.isAnnotationPresent(OnClick.class)) {
OnClick annotation = method.getAnnotation(OnClick.class);
int[] resIds = annotation.value();
for (int resId : resIds) {
final View view = target.findViewById(resId);
final Object proxyInstance = Proxy.newProxyInstance(InjectHelper.class.getClassLoader(), new Class[]{View.OnClickListener.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
return method.invoke(target, view);
}
});
view.setOnClickListener((View.OnClickListener) proxyInstance);
}
}
}
}
以上是关于动态代理+注解+反射实现View的点击事件绑定的主要内容,如果未能解决你的问题,请参考以下文章
ButterKnife -- 源码分析 -- 在‘编译期’间生成findViewById等代码
ButterKnife -- 源码分析 -- 在‘编译期’间生成findViewById等代码
IOC 控制反转Android 事件依赖注入 ( 事件依赖注入具体的操作细节 | 创建 事件监听器 对应的 动态代理 | 动态代理的数据准备 | 创建调用处理程序 | 创建动态代理实例对象 )(代码片
IOC 控制反转Android 事件依赖注入 ( 事件依赖注入具体的操作细节 | 获取要注入事件的 View 对象 | 通过反射获取 View 组件的事件设置方法 )