2012-05-18 15 views
12

को बंद करने का कारण बनता है मैंने अपने आवेदन में दो देशी पुस्तकालयों (.so) को एकीकृत किया है। पुस्तकालय ठीक संकलित करते हैं और मैं उन्हें अपने आवेदन में भी लोड कर सकता हूं। पहली बार जब मैं लाइब्रेरी की मूल विधि का आह्वान करता हूं तो यह ठीक काम करता है, लेकिन यदि मैं गतिविधि में फिर से एक ही विधि को कॉल करता हूं तो एप्लिकेशन बंद हो जाता है।किसी गतिविधि में तृतीय पक्ष लाइब्रेरी के दो बार देशी विधि को कॉल करने से एंड्रॉइड एप्लिकेशन

समस्या

मैं का सामना करना पड़ रहा बिल्कुल वैसा ही जैसा कि यहाँ में उल्लेख किया है:
http://grokbase.com/t/gg/android-ndk/1226m68ydm/app-exit-on-second-native-call

समाधान है कि काम करता है एक और गतिविधि में देशी विधि आह्वान और System.exit के माध्यम से जबरदस्ती उसे बंद करने के लिए है (0) । आलेख के बाद मैंने सफल ऑपरेशन के बाद पॉइंटर्स को कॉल की विधि में सेट करने की कोशिश की, लेकिन इससे भी मेरी मदद नहीं हुई। सिस्टम.लोड लाइब्रेरी() द्वारा लोड होने के बाद भी लाइब्रेरी को अनलोड करना संभव नहीं है।

मैं एक नई गतिविधि के बिना मूल तरीकों से अधिक बार कॉल करना चाहता हूं। इस मुद्दे को हल करने के लिए कोई विचार?

(मैं अंत में एक समाधान नहीं मिला ... यहाँ है)

ठीक है, मैं अंत में इस समस्या को हल करने के लिए एक रास्ता मिल गया है। समाधान वास्तव में बहुत आसान है। अन्य पुस्तकालयों को लोड और अनलोड करने के लिए एक और स्वतंत्र देशी पुस्तकालय (उपयोगिता पुस्तकालय) बनाएं। हमें क्या करना है उपयोगिता की मूल विधि में dlopen() और dlclose() का उपयोग करना है। हम सिस्टम.लोड लाइब्रेरी() के माध्यम से पहले उपयोगिता पुस्तकालय लोड कर सकते हैं।

तो उपयोगिता पुस्तकालय हम क्या करने की जरूरत के मूल विधि में है:

उपयोग #include <dlfcn.h> // इस dlopen कॉल करने के लिए आवश्यक है() और dlclose() काम करता है।

void *handle; 
typedef int (*func)(int); // define function prototype 
func myFunctionName; // some name for the function 

ओपन dlopen के माध्यम से पुस्तकालय():

हैंडलर और समारोह प्रोटोटाइप प्रदान करें

handle = dlopen("/data/data/my.package.com/lib/somelibrary.so", RTLD_LAZY); 

जाओ और पुस्तकालय के समारोह कॉल करें:

myFunctionName = (func)dlsym(handle, "actualFunctionNameInLibrary"); 
myFunctionName(1); // passing parameters if needed in the call 

अब जब कि कॉल किया जाता है इसे dlclose():

dlclose(handle); 

आशा है कि इससे अन्य लोगों को एक ही समस्या का सामना करने में मदद मिलेगी।

+0

आप dlclose (हैंडल) कहां करते हैं? मेरा मतलब गतिविधि या जेएनआई कोड में है? –

+0

इसकी जेएनआई कोड में। यह dlfcn.h हेडर फ़ाइल के माध्यम से उपलब्ध एक फ़ंक्शन है। – ZakiMak

+0

ठीक है, मुझे लगता है कि आप इस सी कक्षा में अन्य पुस्तकालयों को लोड और अनलोड करते हैं। लेकिन मुझे इसे अपने जावा कोड से कैसे लिंक करना चाहिए? –

उत्तर

5

तो ... मेरा समाधान एक सेवा शुरू कर रहा था जो साझा लाइब्रेरी कोड चलाता है, इस सेवा के पास एक अलग प्रक्रिया नाम है (आप इसे एंड्रॉइड मैनिफेस्ट में सेट कर सकते हैं), क्योंकि यह एक अलग प्रक्रिया है जिसे आप इसे मार सकते हैं (का उपयोग करते हुए Process.killProcess (Process.myPid()) जब यह चल रहा है, किसी भी तरह से अपने आवेदन को प्रभावित किए बिना खत्म।

मेरे लिए बहुत अच्छी तरह से काम किया, आशा है कि यह मदद करता है किसी और।

+0

मुझे लगता है कि यह एक साफ समाधान है। करना मुश्किल है लेकिन बेहतर है। – ezefire

2

इस रूप में शीर्ष हिट है इस मुद्दे के लिए और जैसा कि मुद्दा अभी भी मौजूद है, ऐसा लगता है कि जाकीमाक हमारे साथ साझा दृष्टिकोण अभी भी सबसे लोकप्रिय समाधान है।

जो दूसरों इसे लागू करने के लिए कर सकते हैं और नवीनतम Android रिलीज के लिए थोड़ा और विस्तार चाहते हैं के लिए, यहाँ कुछ नोटों के रूप में मैं इस के माध्यम से ठोकर खाई जो मैंने बनाया है:

  • सबसे पहले, वहाँ एक समाधान है जो अब गिटहब पर इस दृष्टिकोण को लागू करता है। मैंने इसे व्यक्तिगत रूप से आजमाया नहीं है, लेकिन मैंने इसे संदर्भ के रूप में उपयोग किया है। यह देखने में बहुत उपयोगी है कि एंड्रॉइड.एमके फ़ाइल कैसे संरचित होती है और पुस्तकालय कैसे खोला जाता है और विधियों को कैसे बुलाया जाता है। लिंक यहां है: https://github.com/jhotovy/android-ffmpeg
  • मूल लाइब्रेरी फ़ोल्डर का पथ एंड्रॉइड रिलीज़ पर बदलता है और यह भी हर बार जब आप ऐप चलाते हैं तो यह बदलता प्रतीत होता है (हालांकि यह केवल डीबग मोड में हो सकता है)। किसी भी तरह से, यदि संभव हो तो जावा विधि को कॉल करने से पथ को पार करना सबसे अच्छा है।

जावा रैपिंग वर्ग में:

import android.content.Context; 
import android.util.Log; 

public class FfmpegJNIWrapper { 

    //This class provides a Java wrapper around the exposed JNI ffmpeg functions. 

    static { 
     //Load the 'first' or 'outer' JNI library so this activity can use it 
     System.loadLibrary("ffmpeg_wraper_multi_invoke_jni"); 
    } 

    public static int call_ffmpegWrapper(Context appContext, String[] ffmpegArgs) { 
     //Get the native libary path 
     String nativeLibPath = appContext.getApplicationInfo().nativeLibraryDir; 

     //Call the method in the first or 'outer' library, passing it the 
     //native library past as well as the original args 
     return ffmpegWrapper(nativeLibPath, ffmpegArgs); 
    } 


    // Native methods for ffmpeg functions 
    public static native int ffmpegWrapper(String nativeLibPath, String[] argv); 

} 

'पहली' या 'बाहरी' देशी पुस्तकालय में: उदाहरण के लिए

JNIEXPORT jint JNICALL Java_com_yourpackage_androidffmpegwrapper_FfmpegJNIWrapper_ffmpegWrapper(JNIEnv *pEnv, jobject pObj, jstring nativeLibPath, jobjectArray javaArgv) { 

    //Get the second or 'inner' native library path 
    char* nativePathPassedIn = (char *)(*pEnv)->GetStringUTFChars(pEnv, nativeLibPath, NULL); 
    char ourNativeLibraryPath[256]; 
    snprintf(ourNativeLibraryPath, sizeof (ourNativeLibraryPath), "%s%s", nativePathPassedIn, "/libffmpeg_wraper_jni.so"); //the name of your ffmpeg library 

    //Open the so library 
    void *handle; 
    typedef int (*func)(JNIEnv*, jobject, jobjectArray); 
    handle = dlopen(ourNativeLibraryPath, RTLD_LAZY); 
    if (handle == NULL) { 
     __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "could not open library: %s", dlerror()); 
     printf("Could not dlopen(\"libbar.so\"): %s\n", dlerror()); 
     return(-1); 
    } 

    //Call the ffmpeg wrapper functon in the second or 'inner' library 
    func reenterable_ffmpegWrapperFunction; 
    reenterable_ffmpegWrapperFunction = (func)dlsym(handle, "Java_com_yourpackage_androidffmpegwrapper_FfmpegJNIWrapper_ffmpegWrapper"); 
    reenterable_ffmpegWrapperFunction(pEnv, pObj, javaArgv); //the original arguments 

    //Close the library 
    dlclose(handle); 

    // return 
    return(1); 
} 
  • Android.mk फ़ाइल एक है इसे विनम्रतापूर्वक रखने के लिए थोड़ा 'flaky'। चूंकि आप एक एंड्रॉइड.एमके फ़ाइल में दो अलग-अलग पुस्तकालयों का निर्माण कर रहे हैं, यह थोड़ा और जटिल हो सकता है कि अन्य एनडीके फाइलें बनाते हैं ताकि अगर आपको कुछ अजीब त्रुटियां मिलें तो इससे पहले कि आप अपनी परियोजना को अलग करना शुरू करें। उदाहरण के लिए: https://stackoverflow.com/a/6243727/334402
संबंधित मुद्दे