看了标题,肯定有人会说我没事吃饱了撑的,谁去实现私有接口啊?当然这是有情景的事,android的SDK中有一个widget叫NumberPicker,这个东西被官方给hide掉了——就是可以看,但是不能用!
这不是开玩笑么!好好的一个组件,不让人用怎么行?来吧,用反射吧!
Class.forName("android.widget.NumberPicker");
很好,搞定,通过getMethod来获得方法,进行调用,嗯嗯嗯,一切都很顺利。突然有一个方法难住了!setOnChangeListener这个方法的参数是在NumberPicker内部定义的一个接口,当然这个接口是public的,但由于整个类都被隐藏了,所以就算是public也无法调用,没办法了,自己搞吧。
public interface OnChangedListener {
void onChanged(NumberPicker picker, int oldVal, int newVal);
}
然后就用asm吧,恩,看了看相关的文档,一头雾水,很高深,不适合我这样的懒人去用嘛~再次放弃!
绝望的时候往往也是希望来的时候,突然想到了动态代理这个东西,动态代理可以实现类似AOP的东西嘛,那我就把onChange中要实现的事情在代理中实现应该就可以了,好吧,来试试看。
Class<?> i = Class.forName("android.widget.NumberPicker$OnChangedListener");
Object listener = Proxy.newProxyInstance(i.getClassLoader(),
new Class<?>[] { i }, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
mYear = (Integer) args[2];
notifyDateChanged();
return null;
}
});
这样可以创建一个“匿名”的listener,实现了OnChangedListener接口,然后就把它作为参数传过去就好了!
Method method = c.getDeclaredMethod("setOnChangeListener", Class
.forName("android.widget.NumberPicker$OnChangedListener"));
method.invoke(numberPicker, listener);
来张截图哈!
这样一个可以响应listener的numberpicker就可以使用了!
当然,也可以把android的源码check out 然后把hide标签去掉,重新编译,然后也可以,不过这样也太暴力了,还是和谐一点比较好!