getOnClickListener() in Android views

user969039 picture user969039 · Jun 25, 2012 · Viewed 13.1k times · Source

I need a getOnClickListener() for Views in Android. This way I can assign a temporary OnClickListener to my Views. I want to use it like this:

private View.OnClickListener oldListener;

public void assignTempListener(View view) {
    oldListener = view.getOnClickListener(); // doesn't exist

    view.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            // some code

            v.setOnClickListener(oldListener);
        }
    });
}

The problem is that this function doen't exist. I also can't inherit from View to create this method, because all kind of Views can be passed to assignTempListener. Is there another way to use this?

Edit: made a small mistake in my code.

Answer

Kevin Coppock picture Kevin Coppock · Feb 21, 2013

You can do this with...REFLECTION. *drum roll*

This route is fraught with peril.

I don't recommend it, as the internal structure of the class can change at any time, but here's how you can do it currently up to Android 4.2.2 if it's truly unavoidable:

/**
 * Returns the current View.OnClickListener for the given View
 * @param view the View whose click listener to retrieve
 * @return the View.OnClickListener attached to the view; null if it could not be retrieved
 */
public View.OnClickListener getOnClickListener(View view) {
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        return getOnClickListenerV14(view);
    } else {
        return getOnClickListenerV(view);
    }
}

//Used for APIs lower than ICS (API 14)
private View.OnClickListener getOnClickListenerV(View view) {
    View.OnClickListener retrievedListener = null;
    String viewStr = "android.view.View";
    Field field;

    try {
        field = Class.forName(viewStr).getDeclaredField("mOnClickListener");
        retrievedListener = (View.OnClickListener) field.get(view);
    } catch (NoSuchFieldException ex) {
        Log.e("Reflection", "No Such Field.");
    } catch (IllegalAccessException ex) {
        Log.e("Reflection", "Illegal Access.");
    } catch (ClassNotFoundException ex) {
        Log.e("Reflection", "Class Not Found.");
    }

    return retrievedListener;
}

//Used for new ListenerInfo class structure used beginning with API 14 (ICS)
private View.OnClickListener getOnClickListenerV14(View view) {
    View.OnClickListener retrievedListener = null;
    String viewStr = "android.view.View";
    String lInfoStr = "android.view.View$ListenerInfo";

    try {
        Field listenerField = Class.forName(viewStr).getDeclaredField("mListenerInfo");
        Object listenerInfo = null;

        if (listenerField != null) {
            listenerField.setAccessible(true);
            listenerInfo = listenerField.get(view);
        }

        Field clickListenerField = Class.forName(lInfoStr).getDeclaredField("mOnClickListener");

        if (clickListenerField != null && listenerInfo != null) {
            retrievedListener = (View.OnClickListener) clickListenerField.get(listenerInfo);
        }
    } catch (NoSuchFieldException ex) {
        Log.e("Reflection", "No Such Field.");
    } catch (IllegalAccessException ex) {
        Log.e("Reflection", "Illegal Access.");
    } catch (ClassNotFoundException ex) {
        Log.e("Reflection", "Class Not Found.");
    }

    return retrievedListener;
}