La reflexión en Android no funciona

I tried using reflection to use a custom List View for an App with target api level 7. The necessary fileds are only available from api level 9 so I attempted to fix that via reflection.

I need to find the protected Method View.overScrollBy( int,int,int,int,int,int,int,int,boolean). When i call

View.getDeclaredMethods() 

and iterate over the Method[] array i find it, but when I try

View.class.getDeclaredMethod(String name, Class...< ? > paramTypes)

I get a NoSuchMethodException. I compared the hard coded Method Name and parameterType values with the values extracted from the method (found via iteration) and they are identical...

private boolean initCompatibility() 
{
Method[] methods = View.class.getDeclaredMethods();
try {
    // The name of the Method i am looking for;
    String OVERSCROLL_S = "overScrollBy";
    for (Method meth : methods) {
        if (meth.getName().equals(OVERSCROLL_S)) {
            mListView_overScrollBy = meth;
            break;
            // method found
        }
    }

    // Params for getDeclaredMethod(…)
    String methodName = "overScrollBy";
    Class[] methodParams =  {  Integer.TYPE, Integer.TYPE, Integer.TYPE, 
            Integer.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE, 
            Integer.TYPE, Boolean.TYPE };

    // works
    Method test =  View.class.getDeclaredMethod(methodName,methodParams);
    // fails
    View.class.getDeclaredMethod(mListView_overScrollBy.getName(), 
               mListView_overScrollBy.getParameterTypes());

    /*
    * I also tried this way around and again the first worked and the second
    * failed, so the input arguments are not the problem...
    * View.class.getDeclaredMethod( mListView_overScrollBy.getName(), 
    *                           mListView_overScrollBy.getParameterTypes() );
    * Method test =  View.class.getDeclaredMethod(methodName,methodParams);
    */

    return true;
    } catch (SecurityException e) {
        e.printStackTrace();
        return false;
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
        return false;
    }
}

I do not understand why the call always works the first time and the does not the second time. Interestingly it also fails when i call only once for View.class.getDeclaredMethod(String name, Class...< ? > paramTypes) and it does not make any difference whether i use the hard coded input values or the one extracted from the method I am looking for...

Does anybody know what the problem is? Thanks

preguntado el 08 de noviembre de 11 a las 13:11

Look at my answer. Could you confirm if your exception is thrown in both debug and run modes? -

Stupid question time! Is this the real code that you are running? Any chance the View you investigate earlier is a different class then the one later? Different import since it's a common class name. -

Another stupid question: Do you get an output at the printStackTrace? I just run your exact code in an emulator, and didn't get an output. Also, when debuging Android apps in eclipse, the line numbers esp. with returns are not correct. So after the 2nd getDeclaredMethod, the IP points to the return statement in the catch block, even if no exception was thrown at all! (encountered such behaviour quite often) -

1 Respuestas

This is very interesting, but it is not Android-specific, I think.

I wrote this small test in plain Java:

    public class ReflectionTest {

        public static void main(String[] args){
            Method[] m = ReflectionTest.class.getDeclaredMethods();
            for (Method method : m) {
                System.out.println(method.getName());
            }               

            try {
                Method m1 = ReflectionTest.class.getDeclaredMethod("d0", int.class, boolean.class);
                if(m1 != null){
                    System.out.println("m1 found!");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } 

            try {
                Method m2 = ReflectionTest.class.getDeclaredMethod("d0", Integer.TYPE, Boolean.TYPE);
                if(m2 != null){
                    System.out.println("m2 found!");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } 

            try {
                Class<?>[] carr = m[1].getParameterTypes();
                Method m3 = ReflectionTest.class.getDeclaredMethod("d0", carr);
                if(m3 != null){
                    System.out.println("m3 found!");
                }
            } catch (Exception e){
                e.printStackTrace();
            } 
        }

        public void d0(int a, boolean b){

        }
    }

In eclipse, if I debug it, the three m1,m2 and m3 are printed. However, if I run it, a NoSuchMethodException is thrown when trying to get m3.

ACTUALIZACIONES:

  • Tested running with jre 7 under linux, and all three m1,m2 and m3 were printed. Perhaps is a problem with jre6? Or is eclipse run configuration?
  • cambiado carr declaration to use method 0 instead of 1: Class<?>[] carr = m[0].getParameterTypes(); as Gray suggested. Now it runs ok but throws exception in debug mode. This means different method order for the returned array m.
  • Update #2 confirmed, I've included a for loop to print the method names. In run mode the order of the method array is reversed compared to debug mode.

respondido 08 nov., 11:21

Your test works fine for me under JRE6 under MacOSX. Maybe a particular JRE version number? - Gray

Have same problem: in eclipse works when debuging, throws exception when running. Win7 64bit, JRE 1.6.0_26-b03 and JDK 1.6.0_20-b02. getDeclaredMethods must have a problem, as it searches for d0([Ljava.lang.String), so a method with String[] argument - king_nak

@Gray That maybe the case. I'm running JRE 1.6.0_07-b06, eclipse 3.6 helios, Windows XP 32bit. - Señor smith

@king_nak thats the exception i'm getting too. Is there a site to search a DB of JRE bugs? - Señor smith

I'm on Mac OSX 10.7.2. java version "1.6.0_26", Java(TM) SE Runtime Environment (build 1.6.0_26-b03-383-11A511), Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02-383, mixed mode) - Gray

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.