14

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

  1. 一个带有 onClickListener 按钮的 App 正在运行
  2. 我的服务在 UI-Thread 中注册了一个 onClickListener + 做一些事情
  3. 我的服务恢复了旧的监听器

如果有 - 方法,那将很容易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

4 回答 4

22

感谢 mihail 的提示(感谢 :)))使用隐藏的 API,我找到了一个解决方案,可以在分配后让听众回来:

该类android.view.View有一个嵌套类static class ListenerInfo,它将所有侦听器存储在视图上(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

于 2013-01-31T10:21:40.633 回答
3

创建实现的类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();
于 2013-01-30T10:50:07.433 回答
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 的对象(并且我们知道您有,因为将新的侦听器设置为按钮),您可以在该活动上添加您的按钮和您的侦听器。使现有按钮不可见。而不是在必要时回滚。

于 2013-01-30T10:48:54.667 回答
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);您正在寻找的听众。myViewmyView

于 2019-04-23T15:52:54.283 回答