Android 如何获取视图的侦听器
我编写与其他应用程序交互的服务。它在已经有侦听器的视图(按钮、文本视图等)上注册侦听器。我需要用我自己的侦听器(works)替换它们,做一些事情,然后注销我的侦听器并恢复旧的侦听器Android 如何获取视图的侦听器,android,listener,Android,Listener,我编写与其他应用程序交互的服务。它在已经有侦听器的视图(按钮、文本视图等)上注册侦听器。我需要用我自己的侦听器(works)替换它们,做一些事情,然后注销我的侦听器并恢复旧的侦听器 正在运行带有onClickListener按钮的应用程序 我的服务在UI线程内注册onClickListener+执行某些操作 我的服务恢复旧的侦听器 如果有一个view.getOnClickListener-方法,这将很容易。然后,我可以保存旧的,并在完成后替换新的侦听器 有没有办法从一个视图中获取侦听器,或者将多
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();
如果我将新的侦听器注册到视图中,旧的侦听器将被覆盖,对吗?如果两个侦听器(“新的”和“旧的”)同时存在也可以。只有旧的不能消失
编辑:不幸的是,我无法在分配时保存侦听器。我需要从视图组件中向后获取它
谢谢制作两个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");
}
因此,如果您无法访问按钮创建位置的代码,则无法获取按钮的现有侦听器
但如果您有权访问活动对象(我们知道您有权访问,因为将new listener设置为button),您可以在该活动上添加按钮和侦听器。使现有按钮不可见。然后在必要时回滚。创建实现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());
或者,您可以创建实例并重用它们:
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();
感谢mihail对隐藏API的提示(谢谢:)),我找到了一个解决方案,可以在分配任务后让侦听器返回:
android.view.view类有一个嵌套类静态类ListenerInfo
,它将所有侦听器存储在一个视图上(API 14+)。在旧版本中,监听器是android.view.view
中的私有字段
该字段可以通过反射进行访问。就我而言(API 14+)
在那段代码之后(我错过了很多try-catch块),myListener对象保存了onClickListener的实例,该实例之前已匿名声明给视图。它也适用于任何其他侦听器,只需将“mOnClickListener参数”替换为反射中所需的参数并正确地强制转换即可
请注意,即将发布的版本中的代码更改可能会使其不再工作
在这里找到了最终教程:公共抽象类ReflectionUtils{
私有静态最终字符串listenerInfoFieldName=“mListenerInfo”;
私有静态最终字符串onCLickListenerFieldName=“mOnClickListener”;
公共静态OnClickListener getOnClickListener(视图){
Object listenerInfo=ReflectionUtils.getValueFromObject(视图,listenerInfoFieldName,Object.class);
返回ReflectionUtils.getValueFromObject(listenerInfo、onCLickListenerFieldName、View.OnClickListener.class);
}
公共静态T getValueFromObject(对象对象、字符串字段名、类returnClazz){
返回getValueFromObject(object,object.getClass(),fieldName,returnClazz);
}
私有静态T getValueFromObject(对象对象、类declaredFieldClass、字符串字段名、类returnClazz){
试一试{
Field Field=declaredFieldClass.getDeclaredField(fieldName);
字段。setAccessible(true);
对象值=field.get(对象);
返回返回clazz.cast(值);
}捕获(无此字段例外){
Class superClass=declaredFieldClass.getSuperclass();
if(超类!=null){
返回getValueFromObject(对象、超类、字段名、returnClazz);
}
}捕获(非法访问例外e){
}
返回null;
}
}
调用
OnClickListener OnClickListener=ReflectionUtils.getOnClickListener(myView)myView
上的code>将为您提供您正在寻找的myView
的侦听器。您不能通过setOnClickListener方法设置旧的侦听器吗<代码>setOnClickListener(旧侦听器)代码>否,因为我只知道服务“控制/挂接(通过检测)”的应用程序的小部件。因此,我无法在分配旧侦听器时保存它,因为我没有应用程序的src代码。有了指令插入,我可以获得所有的小部件、按钮等,但我还需要当前的活动侦听器。希望这能让问题变得更清楚。嗨,朋友,你做到了吗?我想做同样的事情@dr.AtZeThanks,但这对我来说不起作用,因为我无法访问应用程序,而该应用程序是为侦听器分配的。我需要后面的监听器和仪器。有了它,我可以得到按钮、视图等等,但我还需要它们的侦听器在插入后恢复它们。否则,当我的指令插入完成后,应用程序将不再可控。我错过了自定义侦听器仍然用它替换旧的侦听器。因此,在您的示例中,listener2
始终替换listener1
。如果旧的仍然存在那就太好了,因为我对第一个侦听器的分配位置的源代码没有影响。我只使用仪器获取视图。所以,当我没有把它保存在crea上时,不存在找回一个听众的“魔力”
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;
}
}