如何获得视图的监听器

时间:2013-01-30 10:27:38

标签: android listener

我编写与其他应用程序交互的服务。它在已有侦听器的视图(按钮,textviews,...)上注册侦听器。我需要用我自己的听众(作品)替换它们,做一些事情然后取消注册我的听众并恢复旧听众。

  1. 带有onClickListener按钮的应用程序正在运行
  2. 我的服务在UI-Thread +内部注册一个onClickListener
  3. 我的服务恢复旧监听器
  4. 如果有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();
    

    如果我将新的侦听器注册到视图中,那么旧的侦听器会被覆盖,对吧?如果两个听众(“新”和“旧”)同时存在也没关系。只有旧的一定不能消失。

    编辑:不幸的是我无法在分配时保存监听器。我需要从视图组件中向后移动它。

    由于

4 个答案:

答案 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的监听器。