cocos2d-x 中多线程的c/c++代码通过JNI调用java代码
2014-01-02 15:49
1923人阅读
转载请注明原地址: http://blog.csdn.net/wu4long/article/details/17757433
这个文章为android multithread in c/c++ to call JNI 的第二篇。 第一篇地址为:http://blog.csdn.net/wu4long/article/details/17756419 上文提到, android的第三种方法,通过 ClassLoader
object
来处理了。
哪怎样处理呢(This requires some effort) ? 下面我就以cocos2d-x的环境来具体描述吧。当然不是这个环境的也可以自己来稍微修改下。 此文方法是参照http://stackoverflow.com/questions/13263340/findclass-from-any-thread-in-android-jni FindClass from any thread in Android JNI不过此文章不是针对cocos2d-x来写的。有些地方给出的代码不严谨。
///return true if success. else return false. boolyour_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(); } 在线程函数中开始调用 your_thread_start_javaVMAttachCurrentThread(),线程结束的地方调用your_thread_stop_javaVMDetachCurrentThread()。 错误处理自己去处理吧。上面的两个函数你可以放置在你的认为合适的地方。当然也可以直接放置在JniHelper的类中。自行处理吧。
为了可以继续使用JniHelper的方法,透明的规避多线程的问题。我们就直接修改JniHelper.cpp文件。
staticjobject gClassLoader; jmethodIDgFindClassMethod; 增加一个新的函数: static void initClassLoaderForMultiThread() {
JNIEnv*env = 0; do { if(! getEnv(&env)) { break; } jclasscocos2dClass = env->FindClass("org/cocos2dx/lib/Cocos2dxRenderer"); if(env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); LOGD("ExceptioninitClassLoaderForMultiThreadcocos2dClass is exception"); break; } ///env->FindClass("java/lang/Class"); jclassclassClass = env->GetObjectClass(cocos2dClass); if(env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); LOGD("ExceptioninitClassLoaderForMultiThreadclassClass is exception"); break; } jclassclassLoaderClass = env->FindClass("java/lang/ClassLoader"); initClassLoaderForMultiThreadclassLoaderClass"break; } jmethodIDgetClassLoaderMethod = env->GetMethodID(classClass,"getClassLoader", "()Ljava//ClassLoader;"); jobjectclassLoader = env->CallObjectMethod(cocos2dClass,getClassLoaderMethod); initClassLoaderForMultiThreadclassLoader"break; } gClassLoader = env->NewGlobalRef(classLoader); jmethodIDfindClassMethod = env->GetMethodID(classLoaderClass,255)">"findClass", "(/String;)/Class;"); gFindClassMethod = findClassMethod; if(env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); gFindClassMethod = NULL; gClassLoader = NULL; initClassLoaderForMultiThreadfindClassMethod"break; } }while(0); } 然后在JniHelper::setJavaVM 函数中调用上面的函数。如下所示:
voidJniHelper::setJavaVM(JavaVM*javaVM) { m_psJavaVM= javaVM;
initClassLoaderForMultiThread();
}
然后修改 getClassID_ 函数. 添加下面灰色阴影的部分。即在原有的FindClass失败的时候, 用我们新的ClassLoader的方法来查找类。 ret =static_cast<jclass>(pEnv->CallObjectMethod(gClassLoader,gFindClassMethod,jstrName));
jclassgetClassID_(constchar*className,65)">JNIEnv*env) { JNIEnv*pEnv = env; jclassret = 0; do { if(! pEnv) { if(! getEnv(&pEnv)) { break; } }
ret = pEnv->FindClass(className); if(! ret) { if(gClassLoader) { if(pEnv->ExceptionCheck()) { pEnv->ExceptionDescribe(); pEnv->ExceptionClear(); } jstring jstrName = (pEnv)->NewStringUTF(className); ret = static_cast<jclass>(pEnv->CallObjectMethod(gClassLoader,jstrName)); if(ret) break; } LOGD("Failed to find class of %s",className); }while(0); returnret; } 然后在你的线程代码中,可以使用JniHelper来调用相应的方法了。
JniHelper::getStaticMethodInfo 等方法和本来单线程的就一样了。
大功告成了。已经可以透明处理多线程了。 如果你的环境不是cocos2dx,只需要修改将上面添加的部分移到你的环境中就可以了。 唯一的区别,就是将这句 jclasscocos2dClass = env->FindClass("org/cocos2dx/lib/Cocos2dxRenderer"); 中的字符串org/cocos2dx/lib/Cocos2dxRenderer 换成你的环境中肯定存在的java类就可以了。
补充线程的资源同步: 如果线程间需要用到java端的资源同步。可以使用jint MonitorEnter(jobject obj); 和 jint MonitorExit(jobject obj); 类似一个简单的同步锁,在Java中我们这样写 synchronized (obj) { 在JNI中,我们使用这组函数这样写。 当然首先通过Jni的方法来获取这个对象。 jobject obj = ….; env->MonitorEnter(obj); //dosomething env->MonitorExit(obj); (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |