下面通过 java 动态代理跟反射 动态为控件设置监听,配合注解可以实现类似bufferkrnif的依赖注入(简单点说就是不通过对View设置监听,直接回调指定的方法)
这里只分析 事件注入原理不涉及注解
对java动态代理不是很熟悉的请看:这里:http://blog.csdn.net/lqb3732842/article/details/58695219
思路步骤:
1:通过反射获得Veiw 的setOnclicListen
2:通过反射获得真实需要被回调的方法
3:创建一个动态代理,并且持有真实对象以及真实回调方法
4:绑定动态代理
5:通过反射调用第一步中的方法(这里就实现了View的setOnClickListener)
6:当view被点击后 会进入到代理处理类中,在代理处理类会回调真实的方法
实现代码Act
/**
* 动态代理实现事件注入(原理)
* 05
* qq:799135138
*/
public class MainActivity extends AppCompatActivity {
private Button bt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt = (Button) findViewById(R.id.bt);
proxySetOnclick();
}
//通过代理为button设置监听
private void proxySetOnclick() {
try {
//反射获得Button的setOnclicListen方法(参数1:方法名;2:方法参数类)
Method setOnClickListener = bt.getClass().getMethod("setOnClickListener", View.OnClickListener.class);
//获得真实回调的方法(后期可以用注解获得这里hardCode了)
Method realClick=this.getClass().getMethod("realClick",View.class);
//创建一个代理
ProxyHandle handle = new ProxyHandle(this, realClick);
//设置代理 返回的是对应的接口 (OnClickListener实例对象)
Object proxyObj = Proxy.newProxyInstance(View.OnClickListener.class.getClassLoader(), new Class[]{View.OnClickListener.class}, handle);
//调用对应View的设置监听方法 之后会到代理handle里去(对象可以用注解获得这里暂不分析)
setOnClickListener.invoke(bt,proxyObj);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
//真实回调方法
public void realClick(View v) {
Toast.makeText(this,"点击了",Toast.LENGTH_SHORT).show();
}
}
代理处理代码:
/**
* Created by 05 on 2017/3/1.
* qq:799135138
*/
public class ProxyHandle implements InvocationHandler {
private Object realObj;
private Method realMethod;
public ProxyHandle(Object realObj,Method realMethod){
this.realObj=realObj;
this.realMethod=realMethod;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//如果真实对象跟方法都不为null 则直接返回真是方法(这里真实方法必须跟接口方法参数保存一致)
if (realObj!=null&&realMethod!=null){
return realMethod.invoke(realObj,args);
}else {
return method.invoke(proxy,args);
}
}
}
效果,全程没设置监听,点击后回调指定方法: