Cache a reference toClassLoader
Object somewhere handy, and issueloadClass
CILS directly. This requires some effort.
What should I do? (This requires some effort )?
Below I will be specific to the cocos2d-x environment to describe. Of course, you can modify the environment by yourself.
This article is based on the http://stackoverflow.com/questions/13263340/findclass-from-any-thread-in-android-jni
FindClass from any thread in Android JNI but this article is not written for cocos2d-x. In some cases, the Code is not rigorous.
/// Return true if success. else return false.
Bool your_thread_start_javaVMAttachCurrentThread ()
{
JNIEnv * env = NULL;
If (JniHelper: getJavaVM ()-> AttachCurrentThread (& env, NULL) <0) return false;
Return true;
}
Void your_thread_stop_javaVMDetachCurrentThread ()
{
JniHelper: getJavaVM ()-> DetachCurrentThread ();
}
Start calling your_thread_start_javaVMAttachCurrentThread () in the thread function, and call your_thread_stop_javaVMDetachCurrentThread () at the end of the thread (). Handle the error.The two functions above can be placed in what you think is appropriate. Of course, it can also be placed directly in the JniHelper class. Handle it by yourself.
In order to continue using JniHelper, the problem of Multithreading can be avoided transparently. We can directly modify the JniHelper. cpp file.
Static jobject gClassLoader;
Static jmethodID gFindClassMethod;
Add a new function:
Static void initClassLoaderForMultiThread ()
{
JNIEnv * env = 0;
Do
{
If (! GetEnv (& env ))
{
Break;
}
Jclass cocos2dClass = env-> FindClass (Org/Cocos2dx/Lib/Cocos2dxRenderer );
If (env-> ExceptionCheck ())
{
Env-> predictiondescribe ();
Env-> ExceptionClear ();
LOGD (ExceptioninitClassLoaderForMultiThread cocos2dClass is exception );
Break;
}
/// Env-> FindClass (java/lang/Class );
Jclass classClass = env-> GetObjectClass (cocos2dClass );
If (env-> ExceptionCheck ())
{
Env-> predictiondescribe ();
Env-> ExceptionClear ();
LOGD (Exception initClassLoaderForMultiThread classClass is exception );
Break;
}
Jclass classLoaderClass = env-> FindClass (java/Lang/ClassLoader );
If (env-> ExceptionCheck ())
{
Env-> predictiondescribe ();
Env-> ExceptionClear ();
LOGD (Exception initClassLoaderForMultiThread classLoaderClass );
Break;
}
JmethodID getClassLoaderMethod = env-> GetMethodID (classClass, getClassLoader,
()Ljava/Lang/ClassLoader ;);
Jobject classLoader = env-> CallObjectMethod (cocos2dClass, getClassLoaderMethod );
If (env-> ExceptionCheck ())
{
Env-> predictiondescribe ();
Env-> ExceptionClear ();
LOGD (Exception initClassLoaderForMultiThread classLoader );
Break;
}
GClassLoader = env-> NewGlobalRef (classLoader );
JmethodID findClassMethod = env-> GetMethodID (classLoaderClass, findClass ,(Ljava/Lang/String ;)Ljava/Lang/Class ;);
GFindClassMethod = findClassMethod;
If (env-> ExceptionCheck ())
{
Env-> predictiondescribe ();
Env-> ExceptionClear ();
GFindClassMethod = NULL;
GClassLoader = NULL;
LOGD (Exception initClassLoaderForMultiThread findClassMethod );
Break;
}
} While (0 );
}
Then, call the above function in the JniHelper: setJavaVM function. As follows:
Void JniHelper: setJavaVM (JavaVM * javaVM)
{
M_psJavaVM = javaVM;
InitClassLoaderForMultiThread ();}
Then modify the getClassID _ function. Add the gray shadow section below. That is, when the original FindClass fails,
Use our new ClassLoader method to find classes.
Ret = static_cast (PEnv-> CallObjectMethod (gClassLoader, gFindClassMethod, jstrName ));
Static jclass getClassID _ (constchar * className, JNIEnv * env)
{
JNIEnv * pEnv = env;
Jclass ret = 0;
Do
{
If (! PEnv)
{
If (! GetEnv (& pEnv ))
{
Break;
}
}
Ret = pEnv-> FindClass (className );
If (! Ret)
{
If (gClassLoader)
{
If (pEnv-> predictioncheck ())
{
PEnv-> predictiondescribe ();
PEnv-> predictionclear ();
}
Jstring jstrName = (pEnv)-> NewStringUTF (className );
Ret = static_cast (PEnv-> CallObjectMethod (gClassLoader, gFindClassMethod, jstrName ));
If (ret) break;
}
LOGD (Failed to find class of % s, className );
Break;
}
} While (0 );
Return ret;
}
Then, in your thread code, you can use JniHelper to call the corresponding method.
JniHelper: getStaticMethodInfo and other methods are the same as those of a single thread.
It's done. Multi-threading can be processed transparently.
If your environment is not cocos2dx, you only need to modify and move the added part to your environment.
The only difference is that
Jclass cocos2dClass = env-> FindClass (Org/Cocos2dx/Lib/Cocos2dxRenderer );
You can replace the org/cocos2dx/lib/Cocos2dxRenderer string with the java class that must exist in your environment.
Resource synchronization of the supplemental thread:
If java-side resource synchronization is required between threads. You can use jint MonitorEnter (jobject obj); and jint MonitorExit (jobject obj );
Similar to a simple synchronization lock, we write this in Java
Synchronized (obj ){
// Dosomething
}
In JNI, we use this set of functions. Of course, we first get this object through the Jni method.
Jobject obj = ....;
Env-> MonitorEnter (obj );
// Dosomething
Env-> MonitorExit (obj );