2011-09-23 9 views
8

पर कॉल करते समय जेएनआई दुर्घटनाग्रस्त हो जाता है मैं एंड्रॉइड एप्लिकेशन में मूल सी कोड से जावा विधि को कॉल करने का प्रयास कर रहा हूं। यह जेएनआई के उपयोग के साथ काफी सरल लगता है, लेकिन अंत में विधि को कॉल करते समय मेरा कोड हमेशा दुर्घटनाग्रस्त हो जाता है। मूल निवासी सी कोड::कॉलवॉइड मोड

JNIEXPORT void JNICALL 
Java_com_path_to_my_package_renderStuff(JNIEnv* env, jobject jobj){ 
//... 
jclass clazz = env->FindClass("com/path/to/the/class"); 
jmethodID showCar = env->GetMethodID(clazz,"showCar","()V"); 
env->CallVoidMethod(jobj,showCar); //If I comment this out, it won't crash 
//... 
} 

जावा कोड: यहाँ मेरी कोड है

public void showCar(){  
    doSomething() 
} 

DoSomething() भी पूरा नहीं हुआ है, मैं एक ब्रेकपाइंट वहाँ है, जो मारा जा कभी नहीं होगा सेट कर सकते हैं। और जैसा ऊपर बताया गया है, जैसे ही मैं CallVoidMethod कॉल पर टिप्पणी करता हूं, यह क्रैश नहीं होगा लेकिन स्पष्ट रूप से शोकार() को कॉल नहीं करेगा। कोई संकेत?

+0

क्या आपने यह सुनिश्चित किया है कि 'FindClass' और' GetMethodID' वास्तव में गैर-नल परिणाम लौट रहे हैं? –

+0

हां, हमने दोनों परिणामों की जांच की है, लेकिन इसमें बाइनरी डेटा या कुछ ऐसा लगता है। यह निश्चित रूप से शून्य नहीं है, हालांकि।दुर्भाग्यवश, एंड्रॉइड एनडीके और जीडीबी के साथ मूल कोड डीबग करना काफी कठिन साबित हुआ, क्योंकि हम सी डीबगर को काम करने के लिए बिल्कुल नहीं मिल सकते हैं। – Lennart

उत्तर

11

4 विचारों को आप प्रदान करने के लिए:

...

jclass clazz = env-> FindClass ("com///वर्ग के लिए पथ /");

क्या आप पुष्टि कर सकते हैं कि नाम "com/path/to/the/MyClass" नहीं है, जहां वर्गनाम अपरकेस 1 वर्ण है और स्पष्ट रूप से नाम "वर्ग" एक आरक्षित शब्द है। आपके उदाहरण में जेएनआई सी प्रतीक नाम "Java_com_path_to_my_package_renderStuff" और FindClass() लुकअप "com/path/to/the/class" के उपयोग के बीच थोड़ी विसंगति है। लेकिन चूंकि आपका स्टैक ओवरफ्लो असंतुष्ट लिंक नहीं है, मैं केवल अनुमान लगा सकता हूं कि प्रदान किया गया आपका उदाहरण स्वयं के अनुरूप नहीं है।

मेरे उदाहरण का उपयोग करके मैं जेएनआई सी प्रतीक नाम "Java_com_path_to_the_MyClass_renderStuff" और "com/path/to/the/MyClass" पर FindClass() लुकअप होने की अपेक्षा करता हूं। अपरकेस का पहला अक्षर और लोअरकेस विधि नाम का पहला अक्षर लिंक प्रयोजनों के लिए महत्वपूर्ण हो सकता है।

...

क्या आप वाकई "jobj" पारित किया जा रहा है के रूप में एक ही प्रकार के "com/path/to// वर्ग" आप देख रहे हैं? जो एक JVM दुर्घटना के कारण के बिना जावा कोड में उस बात को सुनिश्चित करेगा

public void renderStuff() { 
    if((this instanceof com.path.to.the.MyClass) == false) 
     throw new RuntimeException("Unexpected class expected: com.path.to.the.MyClass"); 
    renderStuff_internal(); 
} 
private native void renderStuff_internal(); 

: अपने जावा कोड में हो सकता है कि आप के साथ अपनी मूल लपेट कर सकते हैं। तुम भी अंत बनाने "Java_com_path_to_the_MyClass_renderStuff_1internal" (अतिरिक्त "1" चरित्र का इरादा है)

पर संलग्न करने के लिए "_1internal" अपने सी प्रतीक नाम को समायोजित करने की आवश्यकता होगी ...

शायद बेल्ट कोशिश करते हैं और अपवाद धनुकोष्ठक प्रत्येक कथन के बीच में जाँच के बारे में आप की सूची: सुरक्षा के उल्लंघन की तरह

if(env->ExceptionCheck()) { 
    env->ExceptionDescribe(); 
    env->ExceptionClear(); 
} 

हो जाएगा ताकि पिक बातें जब प्रतिबिंब करने का प्रयास कर जब यह अनुमति नहीं दी जा सकती है।

...

jclass cls = env->GetObjectClass(jobj); // instead of FindClass 
jmethodID mid = env->GetMethodID(cls, "showCar", "()V"); 
if(!mid) return; // whoops method does not exist 
env->CallVoidMethod(jobj, mid); 

एक और विचार FindClass() कॉल दूर करने के लिए। यह किसी भी वर्ग के साथ काम करेगा जो GetMethodID पर काम करता है, जैसे कि डायमिक टाइपिंग/देर से बाध्यकारी।

+0

FindClass के बजाय GetObjectClass() का उपयोग करना मुझे जो जानने की आवश्यकता थी। – Alyoshak