2011-09-01 19 views
6

से जावा क्लास सदस्य को कॉल करना मैं एक ओपनजीएल सी/सी ++ एप्लीकेशन लिख रहा हूं जिसे मैं एंड्रॉइड एनडीके, जेएनआई समर्थन के माध्यम से एंड्रॉइड पर पोर्ट कर रहा हूं। मुझे देशी से संकेतित जावा कॉलबैक से कोड निष्पादित करने में कठिनाइयों का सामना करना पड़ रहा है।नेटिव सी/सी ++ कोड

यहाँ कोड है:

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(…); 
    } 
} 

और मूल कोड में मैं एक समारोह texturesLoaded (है) कि जब कुछ बनावट एक और धागा पर पूरी तरह से लोड किए गए हैं संकेत है और मैं nativeLib.draw से एक ताज़ा मजबूर करने के लिए की जरूरत है (...) जावा पक्ष पर। यहाँ है कैसे मैं यह कर:

मैं JavaVM, jClass, jMethodID JNI_OnLoad पर कैश, और texturesLoaded पर

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; 
... 
} 

और फिर gJObjectCached() मुझे क्या:

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!!!"); 
} 

परिणाम ... मूल पक्ष से मुझे कक्षा मिलती है, मुझे विधि मिलती है, विधि कहा जाता है, लेकिन जब यह पहुंचता है/कैल ls requestRender() अंदर (या GLSurfaceView के किसी भी अन्य सदस्य विधि तक पहुंचने का प्रयास कर रहा है इसे क्रैश!)

मैं CallStaticVoidMethod (gJClass, gjMethodID) के साथ प्रयास नहीं कर सकता; क्योंकि तब मेरे पास अनुरोधकर्ता(); तक पहुंच नहीं है;

कोई विचार या राय, शायद मैं यहां कुछ गलत कर रहा हूं।

धन्यवाद

+0

'requestRender()' जावा में है, तो दुर्घटनाओं आमतौर पर एक अपवाद के साथ कर रहे है। क्या आप उल्लेख कर सकते हैं कि अपवाद क्या है। एंड्रॉइड एडीबी लॉग ऐसी जानकारी प्रकट करना चाहिए। लॉग इन करें [यहां] (http://developer.android.com/guide/developing/debugging/debugging-log.html) लॉग के बारे में पता लगाने के लिए – Warpspace

उत्तर

3

आप वर्ग/उद्देश्य यह है कि आप दूर छिपाया जा वैश्विक संदर्भ बनाना होगा। जिन संदर्भों को आप सहेज रहे हैं वे स्थानीय संदर्भ हैं, जिन्हें थ्रेड में साझा नहीं किया जा सकता है और जब रनटाइम जेएनआई स्थानीय संदर्भ स्टैक को साफ़ करता है तो गायब हो जाता है।

Sun/Oracle documentation for global and local references देखें, और जेएनआई विधियों JNIEnv::NewGlobalRef और JNIEnv::DeleteGlobalRef देखें।

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

gJObjectCached = env->NewGlobalRef(obj); 

(संपादित करें: बाहर कर देता है आप विधि आईडी के लिए वैश्विक संदर्भ की जरूरत नहीं है।)

+0

आपका उत्तर बहुत उपयोगी है, लेकिन यह मेरी समस्या की सहायता नहीं करता है। मेरा वैश्विक कैश्ड jclass और jmethodID मान्य हैं, मैं अपने जावा कॉलबैक तक पहुंच सकता हूं, जो कि उस वर्ग का सदस्य है (यह स्थैतिक नहीं है)। समस्या यह है कि मैं उस कॉलबैक से उस वर्ग के किसी अन्य सदस्य को कॉल नहीं कर सकता, क्योंकि मुझे लगता है कि जॉबजेक्ट I कैश इस बात को इंगित नहीं करता है: "com/android/newlineactivity/NewLineGLSurfaceView" क्योंकि मैं इसे किसी अन्य जेएनवी में कैश करता हूं। तो एक स्थिर सदस्य के लिए यह काम करता है: env-> CallStaticVoidMethod (gJClass, gJMethodID); लेकिन एक गैर स्थैतिक के लिए यह नहीं है: env-> CallVoidMethod (gJObjectCached, gJMethodID); समझ में आता है? – eKKo82

+0

क्या 'gJObjectCached' वैश्विक संदर्भ है, या आपने केवल स्थानीय संदर्भ को संग्रहीत किया है जिसे' cachejavaobject' में पारित किया गया था? –

+0

यह एक वैश्विक संदर्भ है और जब मैं env-> CallVoidMethod (gJObjectCached, gJMethodID) को कॉल करता हूं तो मान्य है; लेकिन कॉलबैक() क्रैश हो जाता है जब यह अनुरोधकर्ता() को आंतरिक रूप से कॉल करता है।मैंने जॉबजेक्ट जॉबजे = एनवी-> न्यू ऑब्जेक्ट (जीजे क्लास, जीजेएम विधिआईडी) की भी कोशिश की; और इसे पास करें, उम्मीद है कि सही env, gjClass और gJMethodID के साथ मैं विधि को कॉल कर सकता हूं और यह काम करेगा ... विधियों को बुलाया जाता है लेकिन अनुरोध पर फिर से दुर्घटनाग्रस्त(); – eKKo82

संबंधित मुद्दे