Hi all.
I'm trying to use a cached instance of my application's primary
Activity's ClassLoader to create and use instances of JAVA objects in
my native code from NATIVE threads. The class loader is cached in the
following way:
- Application's startup Activity creates a startup thread for my
native application to load it's native library
- Startup thread loads the native library and uses a reference to the
startup activity to set native global static references of the JVM (in
order to attach/detach native threads) and the startup Activity (to
obtain its classLoader) using a native function created with javah and
implementing in my native library. Something like
static method_loadClass = NULL;
JNIEXPORT jboolean JNICALL
Java_com_somecompany_startup_MyStartupActivity_setJVMandActivityToNativeApplication(JNIEnv
*pJNIEnv, jobject jMyActivity);
- In that function I successfully use pJNIEnv->FindClass and pJNIEnv-
>GetMethodID and a handful of other JNI calls to create a new global
reference to the startup Activity's class loader, which I expect to be
able to use to call FindClass and GetMethodID from any (properly
attached) native thread in my native application. Something like:
static method_loadClass = NULL;
// Cache a reference to the class loader so we can do FindClass
calls from anywhere in our native code
jclass jMyActivityClass = pJNIEnv-
>GetObjectClass(g_jMyStartupActivity);
if(jMyActivityClass)
{
jmethodID method_getClassLoader = pJNIEnv-
>GetMethodID(jMyActivityClass, "getClassLoader", "()Ljava/lang/
ClassLoader;");
if(method_getClassLoader)
{
jobject myClassLoader = pJNIEnv-
>CallObjectMethod(g_jMyStartupActivity, method_getClassLoader);
if(myClassLoader)
{
g_jClassLoader = pJNIEnv->NewGlobalRef(myClassLoader);
if(g_jClassLoader)
{
jclass jClassLoaderClass = pJNIEnv-
>GetObjectClass(g_jClassLoader);
if(jClassLoaderClass)
{
method_loadClass = pJNIEnv->GetMethodID(jClassLoaderClass,
"loadClass", "(Ljava/lang/String;Z)Ljava/lang/Class;");
pJNIEnv->DeleteLocalRef(jClassLoaderClass);
}
}
pJNIEnv->DeleteLocalRef(myClassLoader);
}
}
pJNIEnv->DeleteLocalRef(jMyActivityClass);
}
- In a separate thread I use my g_jClassLoader reference and
method_loadClass methodID to get jclass references to classes whose
methodID's i want to resolve and subsequently call. This should
theoretically give me the ability to create instances of JAVA classes
in my application's JAVA library and use them as I please... UNLESS
I've completely misunderstood the limitations of JNI.
- What happens instead is that the ClassLoader reference excepts when
I ask for Class references to bogus classes (this is expected) and
returns me references of the type java.lang.Class no matter what kind
of VALID class type I ask for (verified by invoking the toString
method on the jclass references the ClassLoader returns to me).
Subsequent calls to GetMethodID using the jclass references returned
by my cached ClassLoader except with the an exception description in
logcat like:
01-12 11:36:49.663: W/System.err(8902): java.lang.NoSuchMethodError:
getInstance
01-12 11:36:49.668: W/System.err(8902): at
dalvik.system.NativeStart.run(Native Method)
Does anyone have any idea what's going on here? Why are all the
classes returned by my ClassLoader of the type java.lang.Class instead
of the actual class type they are (e.g. com.mycompany.mypkg.myclass)?
I imagine that since I'm using these potentially bogus class
references in my GetMethodID calls that I would indeed get the
NoSuchMethedError that I'm seeing.
Responses that are not useful:
1) "Just globally cache EVERY POSSIBLE JAVA METHOD YOU COULD CONCEIVE
OF USING in your JNI_OnLoad"
2) "Keep a global reference to one class that can perform every
conceivable java call for you!" (although this is KIND of the approach
I'm taking with the classloader trickery).
I came down this road by following this piece of advice from this JNI
tips android dev doc
http://developer.android.com/guide/practices/design/jni.html:
"Cache a reference to the ClassLoader object somewhere handy, and
issue loadClass calls directly. This requires some effort."
Thanks for any and all help and attention.
Best
Some Dev