Invoking reflection APIs correctly - Android

2019-07-03 16:05发布

I am trying to invoke the getSelection method of WebView. I am trying to use the reflection APIs in Android to get the selected text.

I have extended WebView (the new class is named MyWebView) to add some functionality. The method getSelection is invoked like so within MyWebView:

for(Method m : WebView.class.getDeclaredMethods()) {
    if(m.getName().equalsIgnoreCase("getSelection")) {
        m.setAccessible(true);
        String str;
        try {
            Log.v(this.toString(), "is getSelection available? " + m.getModifiers() + " " + m.isAccessible());
            str = (String) m.invoke(this, new Object[] { null });
            Log.v(this.toString(), "String selected = " + str);
            Toast.makeText(context, str, Toast.LENGTH_LONG).show();  

MyWebView is a non-Activity class. Running the code results in the following LogCat output:

08-16 19:15:22.745: W/System.err(23452): java.lang.IllegalArgumentException: object is not an instance of the class
08-16 19:15:22.745: W/System.err(23452):    at java.lang.reflect.Method.invokeNative(Native Method)
08-16 19:15:22.745: W/System.err(23452):    at java.lang.reflect.Method.invoke(Method.java:507)
08-16 19:15:22.745: W/System.err(23452):    at com.englishhelper.bluebottle.EHWebView$3.onTouch(EHWebView.java:210)
08-16 19:15:22.745: W/System.err(23452):    at android.view.View.dispatchTouchEvent(View.java:3934)
08-16 19:15:22.745: W/System.err(23452):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:903)
08-16 19:15:22.745: W/System.err(23452):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
08-16 19:15:22.745: W/System.err(23452):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
08-16 19:15:22.745: W/System.err(23452):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
08-16 19:15:22.745: W/System.err(23452):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
08-16 19:15:22.745: W/System.err(23452):    at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1730)
08-16 19:15:22.745: W/System.err(23452):    at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1142)
08-16 19:15:22.745: W/System.err(23452):    at android.app.Activity.dispatchTouchEvent(Activity.java:2102)
08-16 19:15:22.745: W/System.err(23452):    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1714)
08-16 19:15:22.745: W/System.err(23452):    at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2218)
08-16 19:15:22.745: W/System.err(23452):    at android.view.ViewRoot.handleMessage(ViewRoot.java:1889)
08-16 19:15:22.745: W/System.err(23452):    at android.os.Handler.dispatchMessage(Handler.java:99)
08-16 19:15:22.745: W/System.err(23452):    at android.os.Looper.loop(Looper.java:123)
08-16 19:15:22.745: W/System.err(23452):    at android.app.ActivityThread.main(ActivityThread.java:3691)
08-16 19:15:22.745: W/System.err(23452):    at java.lang.reflect.Method.invokeNative(Native Method)
08-16 19:15:22.745: W/System.err(23452):    at java.lang.reflect.Method.invoke(Method.java:507)
08-16 19:15:22.745: W/System.err(23452):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:847)
08-16 19:15:22.745: W/System.err(23452):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:605)
08-16 19:15:22.745: W/System.err(23452):    at dalvik.system.NativeStart.main(Native Method)

My question is:
1. The invoke method in the Reflection API requires that I pass the object of the class on which I intend to call the method on as the first argument. In this case, it would be an object of class MyWebView. How do I call invoke with an object of type MyWebView?
2. The same code works well in a case where MyWebView is part of the Activity class.

1条回答
我只想做你的唯一
2楼-- · 2019-07-03 16:38

The exception shows that you are inside of an anonymous inner class. The problem is that you are accidentally passing the instance of the inner class instead of the instance of EHWebView.

You can tell that you are inside of an inner class because after the normal class name EHWebView, you see a $3, which simply refers to the 3rd anonymous inner class of EHWebView. Here is the relevant part of the stack trace you posed:

08-16 19:15:22.745: W/System.err(23452):    at com.englishhelper.bluebottle.EHWebView$3.onTouch(EHWebView.java:210)

Typically, anonymous inner classes are event handlers or runnables. They appear often and many people are not even aware they are using them.

You are passing this to the invoke() method. Inside of an inner class, this refers to the instance of that inner class instead of the instance of the outer class EHWebView.

To solve the problem, pass the reference of the outer class by removing this an instead using EHWebView.this:

        str = (String) m.invoke(EHWebView.this, new Object[] { null });
查看更多
登录 后发表回答