最近准备入门学习Android的hook框架,因为涉及到Java反射,于是就用这个例子来复习一下Java反射的应用吧。
首先确定我们要实现的效果是
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "fuc you", Toast.LENGTH_SHORT).show();
}
});
跟进setOnClickListener方法,看看底下做了些什么:
public void setOnClickListener(@Nullable OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
ListenerInfo getListenerInfo() {
if (mListenerInfo != null) {
return mListenerInfo;
}
mListenerInfo = new ListenerInfo();
return mListenerInfo;
}
static class ListenerInfo {
...
public OnClickListener mOnClickListener;
...
}
setOnClickListener方法最终将listener对象赋给了View的成员变量mListenerInfo里面的mOnClickListener成员变量,也就是
View.mListenerInfo.mOnClickListener = listener;
所以我们反射的思路是:
- 从btn中获取实例mListenerInfo;
- 设置mListenerInfo的属性mOnClickListener为我们自定义的listener
代码:
//反射修改监听器
Class viewClazz = View.class;
try {
Field infoField = viewClazz.getDeclaredField("mListenerInfo");
infoField.setAccessible(true); //无视访问修饰符
Object listenerInfo = infoField.get(btn);
Class infoClazz = Class.forName("android.view.View$ListenerInfo");
Field listenerField = infoClazz.getDeclaredField("mOnClickListener");
listenerField.setAccessible(true); //无视访问修饰符
listenerField.set(listenerInfo, new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "Hello!", Toast.LENGTH_SHORT).show();
}
});
} catch (Exception e) {
e.printStackTrace();
}