Android通过反射设置按钮的事件监听器

最近准备入门学习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;

所以我们反射的思路是:

  1. 从btn中获取实例mListenerInfo;
  2. 设置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();
}

猜你喜欢

转载自blog.csdn.net/mingc0758/article/details/78825485