从本地C/C++代码中调用JAVA类成员

 2023-01-20    320  

问题描述

我正在编写一个OpenGL C/C ++应用程序,该应用程序正在通过Android NDK(JNI支持)移植到Android.我很难从本机发出的Java回调执行代码.

这是代码:

从本地C/C++代码中调用JAVA类成员

class OpenGLSurfaceView extends GLSurfaceView 
{
…
     public OpenGLSurfaceView(Context context, int deviceWidth, int deviceHeight) 
    {
        super(context);
        nativeObj = new NativeLib();
        mRenderer = new OpenGLRenderer(context, nativeObj, deviceWidth, deviceHeight);
        setRenderer(mRenderer);
        setRenderMode(RENDERMODE_WHEN_DIRTY);
    }
…
    private void CallBack()
    {
        // force redraw
        requestRender();
    }
}


class OpenGLRenderer implements GLSurfaceView.Renderer 
{
    …
public void onSurfaceCreated(GL10 gl, EGLConfig config) 
    {
        nativeObj.init(…);
        nativeObj.cachejavaobject(JNIEnv *env, jobject obj); // for caching obj on native side
    }

    public void onSurfaceChanged(GL10 gl, int w, int h) 
    {
    }

    public void onDrawFrame(GL10 gl) 
    {
        nativeObj.draw(…);
    }
}

和本机代码中有一个函数纹理(),当某些纹理完全加载在另一个线程上时,我需要在Java侧的Nativelib.draw(…)刷新刷新.这是我的方式:

我在JNI_ONLOAD上缓存Javavm,Jclass,Jmethodid和gjobjectcached

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved)
{
gJVM = jvm;  // cache the JavaVM pointer

LogNativeToAndroidExt("JNILOAD!!!!!!!!!!");
JNIEnv *env;
int status = gJVM->GetEnv((void **)&env, JNI_VERSION_1_6);
if(status < 0)
{
    LogNativeToAndroidExt("Failed to get JNI environment, assuming native thread");
    status = gJVM->AttachCurrentThread(&env, NULL);
    if(status < 0)
    {
        LogNativeToAndroidExt("callback_handler: failed to attach current thread");
        return JNI_ERR;
    }
}

gJClass = env->FindClass("com/android/newlineactivity/NewLineGLSurfaceView");
if(gJClass == NULL)
{
    LogNativeToAndroidExt("Can't find Java class.");
    return JNI_ERR;
}

gJMethodID = env->GetMethodID(gJClass, "callback", "()V");
if(gJMethodID == NULL)
{
    LogNativeToAndroidExt("Can't find Java method void callback()");
    return JNI_ERR;
}

return JNI_VERSION_1_6;

}

JNIEXPORT void Java_com_android_OpenGL_NativeLib_cachejavaobject(JNIEnv* env, jobject obj)
{
    // cache the java object
    gJObjectCached = obj;
...
}

然后在纹理上()我做:

void texturesLoaded()
{
    // Cannot share a JNIEnv between threads. You should share the JavaVM, and use JavaVM->GetEnv to discover the thread's JNIEnv
    JNIEnv *env = NULL;
    int status = gJVM->GetEnv((void **)&env, JNI_VERSION_1_6);
    if(status < 0)
    {
        LogNativeToAndroidExt("callback_handler: failed to get JNI environment, assuming native thread");
        status = gJVM->AttachCurrentThread(&env, NULL);
        if(status < 0)
        {
            LogNativeToAndroidExt("callback_handler: failed to attach current thread");
            return;
        }
    }

    LogNativeToAndroidExt("Calling JAVA method from NATIVE C/C++");
    env->CallVoidMethod(gJObjectCached, gJMethodID);
    LogNativeToAndroidExt("DONE!!!");
}

结果…从本地侧我获得了类,我得到了方法,方法是被调用的,但是当它到达/呼叫requestRender()内部(或尝试访问任何其他成员的glsurfaceview方法,它会崩溃!)

我不能尝试使用CallstaticVoidMethod(GJClass,gjmethodid);因为那时我无法访问requestrender();

任何想法或意见,也许我在这里做错了什么.

谢谢

推荐答案

您需要将全局参考创建到您藏起来的类/对象.您保存的参考文献是本地参考,它不能在线程上共享,并且当运行时清理JNI本地参考堆栈时消失.

查看,然后查看JNI方法 JNIEnv::NewGlobalRef 和 JNIEnv::DeleteGlobalRef .

gJClass = env->NewGlobalRef(env->FindClass( ... ));

gJObjectCached = env->NewGlobalRef(obj);

(编辑:事实证明您不需要方法ID的全局引用.)

以上所述是小编给大家介绍的从本地C/C++代码中调用JAVA类成员,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!

原文链接:https://77isp.com/post/26076.html

=========================================

https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。