背景
我们都知道Java内存模型和C++内存模型不同,而且是分开存储和管理的。做NDK开发的小伙伴经常遇到这样一个问题:在Java层new一个对象,这个对象无法直接操作C++对象的内容。本文章就是为了解决这个问题。
解决方案
我这里想到两种方法可以实现Java对象和C++对象进行一一映射。
方案一:Java调用JNI方法new一个C++对象指针,并把指针转成long类型返回给Java
JNI代码如下:
jlong CreateGLThreadHandle(JNIEnv *env, jobject thiz) {
GLRender *glRender = new GLRender();
if (GL_RENDER_JNI_DEBUG) {
DFLOGI(GL_RENDER_JNI_TAG, "CreateGLThreadHandle() handle = %ld", (long) glRender);
}
return (long) glRender;
}
Java代码如下,(这里使用Kotlin,原理一样)
class NativeGLRenderProxy {
private var nativeGLRenderHandle: Long = INIT_HANDLE
fun setNativeGLRenderHandle(nativeGLRenderHandle: Long) {
if (INIT_HANDLE == nativeGLRenderHandle) {
throw RuntimeException("Native GLRender handle is InValid")
}
this.nativeGLRenderHandle = nativeGLRenderHandle
}
}
在返回C++对象指针时,NativeGLRenderProxy对象调用setNativeGLRenderHandle
将Long类型指针对象nativeGLRenderHandle
保存对象内部
fun createGLRenderHandle(): NativeGLRenderProxy {
val nativeGLRenderProxy = NativeGLRenderProxy()
val nativeGLRenderHandle = nativeCreateGLRenderHandle()
nativeGLRenderProxy.setNativeGLRenderHandle(nativeGLRenderHandle)
return nativeGLRenderProxy
}
方案二: 在JNI方法new C++对象后是将C++对象类似Java反射的方式设置给Java对象,这样JNI方法就必须有一个jmethodID对象
//对应com/yj/player/render/NativeGLRenderProxy类的setNativeGLRenderHandle方法
jmethodID setNativeGLRenderHandle;
//注册JNI方法
static jint registerNativeGLRenderMethods(JNIEnv *env) {
jclass clazz = env->FindClass("com/yj/player/render/NativeGLRenderProxy");
if (clazz == nullptr) {
return JNI_ERR;
}
if (env->GetMethodID(clazz, "setNativeGLRenderHandle","(J)V")) {
return JNI_ERR;
}
return JNI_OK;
}
//在JNI方法中callback回调到Java对象的方法中
void CreateGLThreadHandle(JNIEnv *env, jobject thiz) {
GLRender *glRender = new GLRender();
if (GL_RENDER_JNI_DEBUG) {
DFLOGI(GL_RENDER_JNI_TAG, "CreateGLThreadHandle() handle = %ld", (long) glRender);
}
env->CallVoidMethod(thiz, setNativeGLRenderHandle, (long)glRender);
}
网友评论