- Home /
NoSuchMethodError calling android method
Hi all,
I am trying to use native android functions to insert an image I've saved to disk to the device's gallery. This should be just case of one simple call to this insertImage function but I keep getting an exception whenever I try to make the call. Here's my code;
AndroidJavaClass player = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = player.GetStatic<AndroidJavaObject>("currentActivity");
AndroidJavaObject contentResolver = currentActivity.Call<AndroidJavaObject>("getContentResolver");
AndroidJavaClass media = new AndroidJavaClass("android.provider.MediaStore$Images$Media");
media.CallStatic<string>("insertImage ", contentResolver, destination, "Affermational Image", "AFFIRMATIVE");
And here's the exception which is getting thrown on the last line;
"java.lang.NoSuchMethodError: no static method \"Landroid/provider/MediaStore$Images$Media;.insertImage (Landroid.app.ContextImpl$ApplicationContentResolver;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;\""
Obviously it's saying the method doesn't exist but does anyone know why?
Answer by saschandroid · Jan 29, 2016 at 07:29 AM
I don't know if this could be the problem, but you have a whitespace in your java function string:
media.CallStatic<string>("insertImage ",
Well Duh. Don't I feel stupid. That fixed it. Thanks!
Answer by Bunny83 · Jan 29, 2016 at 01:44 AM
Well, the problem is how Unity's wrapper classes are determine the method signatures. Unity simply reads the .NET type of the passed parameters and converts them to the proper Java type. This usually works perfect for most primitive types. However it's a problem with reference types.
You used "getContentResolver" which returned some implementation of the abstract android.content.ContentResolver
class. The signature of insertImage has this abstract class as type argument. However you actually pass a concrete implementation of that abstract class.
So Unity detemines the type of the passed class which is Landroid.app.ContextImpl$ApplicationContentResolver
but the required type is Landroid.content.ContentResolver
. That's why it can't automatically find the method you want to call. That means you can't use the wrapper class AndroidJavaObject to call that method in this case and have to do it "manually". You need to use the methods from the AndroidJNI class (which are also used by AndroidJavaObject and AndroidJavaClass internally).
I'm not that fit with JNI, but you basically need:
GetMethodID and pass the class reference (you get that from your AndroidJavaObject with GetRawClass), the method name and the method signature. The signature should be
"(Landroid.content.ContentResolver;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
. For reference here's the oracle documentation of the JNI method signature syntaxNext you need to create your parameter array for calling that method. You can use the methods from AndroidJNIHelper, specifically CreateJNIArgArray and when done don't forget DeleteJNIArgArray. Keep in mind that for java object references you need the actual object reference and not the wrapper class, so use GetRawObject.
Once you have the methodID and the parameter array ready, you have to pick the right "call" method. Since you should get a string back, you probably want to use AndroidJNI.CallStaticStringMethod
Keep in mind that you have to clean up almost everything manually. So be careful what you allocate and make sure you either destroy / delete the object you created or make sure Dispose() is called on it.
I just checked it. CreateJNIArgArray already does a lot for you. It creates native java strings for your .NET string parameters and it also calls "GetRawObject" if you pass a AndroidJavaObject to that method.
Thanks for going to the trouble of explaining that. I wasn't aware of the AndroidJNI options. However it seems in this case that's not needed. As @saschandroid pointed out I just had some extra whitespace causing problems. I removed it and it all seemed to work fine.