我编写与其他应用程序交互的服务。它在已有侦听器的视图(按钮,textviews,...)上注册侦听器。我需要用我自己的听众(作品)替换它们,做一些事情然后取消注册我的听众并恢复旧听众。
如果有view.getOnClickListener
方法,那将很容易。然后我可以保存旧的并在我完成后替换新的听众。
有没有办法从视图中获取侦听器,或者有多个绑定到一个视图的同一类型的侦听器?
Button btn = (Button) findViewById(R.id.btn1);
btn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//do something
}
});
// I need to do, but found no solution for that.
View.OnClickListener oldListener = btn.getOnClickListener();
如果我将新的侦听器注册到视图中,那么旧的侦听器会被覆盖,对吧?如果两个听众(“新”和“旧”)同时存在也没关系。只有旧的一定不能消失。
编辑:不幸的是我无法在分配时保存监听器。我需要从视图组件中向后移动它。
由于
答案 0 :(得分:20)
感谢mihail的提示(感谢:) :))使用隐藏的API ,我找到了一个解决方案,在分配后让一个监听器回来:
android.view.View
类有一个嵌套类static class ListenerInfo
,它存储View(API 14+)上的所有侦听器。在旧版本中,侦听器是android.view.View
中的私有字段。
可以使用反射访问该字段。就我而言(API 14+),
// get the nested class `android.view.View$ListenerInfo`
Field listenerInfoField = null;
listenerInfoField = Class.forName("android.view.View").getDeclaredField("mListenerInfo");
if (listenerInfoField != null) {
listenerInfoField.setAccessible(true);
}
Object myLiObject = null;
myLiObject = listenerInfoField.get(myViewObj);
// get the field mOnClickListener, that holds the listener and cast it to a listener
Field listenerField = null;
listenerField = Class.forName("android.view.View$ListenerInfo").getDeclaredField("mOnClickListener")
if (listenerField != null && myLiObject != null) {
View.OnClickListener myListener = (View.OnClickListener) listenerField.get(myLiObject);
}
在那段代码之后(我错过了很多try-catch-blocks),myListener对象保存了之前匿名声明的onClickListener实例。它也适用于任何其他侦听器,只需将“mOnClickListener参数”替换为您在反射中所需的参数并正确投射它。
请注意,即将发布的版本中的代码更改可能会使其无法正常工作。
在这里找到最终的教程:http://andwise.net/?p=161
答案 1 :(得分:2)
创建实现OnClickListener
public static class MyClickListener1 implements OnClickListener{
Activity mActivity;
MyClickListener1(Acivity activity){
mActivity=activity;
}
@Override
public void onClick(View v) {
//do something
}
}
public static class MyClickListener2 implements OnClickListener{
@Override
public void onClick(View v) {
//do something
}
}
在您的代码中,您可以轻松使用它们:
btn.setOnClickListener(new MyClickListener1(this));
btn.setOnClickListener(new MyClickListener2());
或者您可以创建实例并重复使用它们:
OnClickListener listener1 = new MyClickListener1(this);
OnClickListener listener2 = new MyClickListener2();
btn.setOnClickListener(listener1);
btn.setOnClickListener(listener2);
您还可以定义构造函数以在这些类中传递您需要的任何内容。我通常会像MyClickListener1
编辑:如果您希望在按钮中拥有类似对象的侦听器,则可以使用该标记。
btn.setTag(listener1);
btn.setOnClickListener(listener1);
然后使用
OnClickListener old_listener = (OnClickListenr)btn.getTag();
答案 2 :(得分:0)
创建两个OnCLickListener实例并将第一个或第二个分配给按钮:
Button b = (Button) findViewById(R.id.Button1);
OnClickListener listener_new = new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("APP", "NEW CLICK LISTENER ACTIVE");
}
};
OnClickListener listener_old = new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("APP", "OLD CLICK LISTENER ACTIVE");
}
};
//setting listener
b.setOnClickListener(listener_old);
b.callOnClick();
//changing listener
b.setOnClickListener(listener_new);
b.callOnClick();
//return your old listener!
b.setOnClickListener(listener_old);
b.callOnClick();
增加:
OnClickListener是Button类的受保护字段,继承自View类。字段“mOnClickListener”的名称。我甚至无法通过反思得到它。
void getListener(Button b) {
java.lang.reflect.Field field = getClass().getSuperclass().getSuperclass().getDeclaredField("mOnClickListener");
}
因此,如果您无法访问创建的代码,则无法获取Button的现有侦听器。
但是如果你有权访问Activity的对象(我们知道你有因为将新的监听器设置为按钮),你可以在监视器上添加你的按钮。使现有按钮不可见。而且在必要时回滚。
答案 3 :(得分:0)
public abstract class ReflectionUtils {
private static final String listenerInfoFieldName = "mListenerInfo";
private static final String onCLickListenerFieldName = "mOnClickListener";
public static OnClickListener getOnClickListener(View view){
Object listenerInfo = ReflectionUtils.getValueFromObject(view, listenerInfoFieldName, Object.class);
return ReflectionUtils.getValueFromObject(listenerInfo, onCLickListenerFieldName, View.OnClickListener.class);
}
public static <T> T getValueFromObject(Object object, String fieldName, Class<T> returnClazz){
return getValueFromObject(object, object.getClass(), fieldName, returnClazz);
}
private static <T> T getValueFromObject(Object object, Class<?> declaredFieldClass, String fieldName, Class<T> returnClazz){
try {
Field field = declaredFieldClass.getDeclaredField(fieldName);
field.setAccessible(true);
Object value = field.get(object);
return returnClazz.cast(value);
} catch (NoSuchFieldException e) {
Class<?> superClass = declaredFieldClass.getSuperclass();
if(superClass != null){
return getValueFromObject(object, superClass, fieldName, returnClazz);
}
} catch (IllegalAccessException e) {
}
return null;
}
}
在OnClickListener onClickListener = ReflectionUtils.getOnClickListener(myView);
上调用myView
将使您正在寻找myView
的监听器。