Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android multithread in c/c++ to call JNI

android multithread in c/c++ to call JNI

編輯:關於Android編程

 

 

android的c/c++調用java的代碼 都是通過jni的。

但如果你在c/c++新建自己的線程,然後在線程上通過jni調用java的代碼,那就麻煩來了。 找不到你需要調用的class。

怎麼辦?

 

Android裡面有說明,http://developer.android.com/training/articles/perf-jni.html 。

 

 

造成這個原因是:

You can get into trouble if you create a thread yourself (perhaps by callingpthread_create and then attaching it with AttachCurrentThread). Now the stack trace looks like this:

    dalvik.system.NativeStart.run(Native Method)

The topmost method is NativeStart.run, which isn't part of your application. If you call FindClass from this thread, the JavaVM will start in the system class loader instead of the one associated with your application, so attempts to find app-specific classes will fail.

也就是說,當前java的VM的線程的CallStack是
 dalvik.system.NativeStart.run(Native Method)

JavaVM將使用系統的class loader而不是你的應用使用的class loader. 從而去找應用自身的類,將會失敗。

 

android也給出了幾個解決方案:

There are a few ways to work around this:

 

 

  • Do your FindClass lookups once, in JNI_OnLoad, and cache the class references for later use. AnyFindClass calls made as part of executing JNI_OnLoad will use the class loader associated with the function that called System.loadLibrary (this is a special rule, provided to make library initialization more convenient). If your app code is loading the library, FindClass will use the correct class loader.
  • Pass an instance of the class into the functions that need it, by declaring your native method to take a Class argument and then passing Foo.class in.
  • Cache a reference to the ClassLoader object somewhere handy, and issue loadClass calls directly. This requires some effort.
    第一種方法就是通過在本來的java線程調用c/c++的時候,來獲取相應的jclass,然後緩存起來。 一般做法就是在JNI_OnLoad方法處理。 這個是有局限的。如果你的類不多,這樣處理還是可行的。 第二種方法,網上的例子比較多,就是在本來的java線程中調用自定義的native函數。從而在native中緩存此對象。然後在新建的線程裡面通過此對象來獲取相應的class。 這個方法和上面的類似。如果類過多,就需要多個此對象。 網上有此代碼。不過有些地方描述不清楚。我這邊總結一下: Java的代碼 void setJNIEnv(); 在應用開始的地方,調用此方法,一般是Activity的onCreate。 在c/c++端native文件中:

    JavaVM *g_jvm = NULL;
    jobject g_obj = NULL;
    JNIEXPORT void Java_YOURCLASS_setJNIEnv( JNIEnv* env, jobject obj)
    {
    (*env)->GetJavaVM(env,&g_jvm);
    g_obj = (*env)->NewGlobalRef(env,obj);
    }
    這樣就建立起了全局的object。 然後在你的c/c++的線程函數中: in your thread fund:

    JNIEnv* env = NULL;

    if( g_jvm->AttachCurrentThread(&env,NULL) < 0) { /// your error process. } jclass cls = (*env)->GetObjectClass(env,g_obj);
    if(cls == NULL)
    { ///your error process.
    } ///獲取到jclass, 就可以調用此class的方法了。 /// GetMethodID 和 CallVoidMethod 等各種jni方法可以調用。 class參數將cls放入。 …….
    在你的線程結束的地方:調用

    g_jvm->DetachCurrentThread();

    既:一個native線程,開始必須調用 AttachCurrentThread. 結束調用 DetachCurrentThread。 不建議多次調用 AttachCurrentThread / DetachCurrentThread。否則可能會造成虛擬機的內存洩漏問題。 因為調用 AttachCurrentThread 是java虛擬機要創建java端的線程與之對應。 這個開銷大家自己去想吧。呵呵。因此,一個線程just call one time。
    從上面的過程來看,它回避了 env->FindClass的問題。 哪有沒有更好的方法呢? 差不多就是android的第三種方法,通過ClassLoader object來處理了。

    這裡寫的過多了,新開第二篇來描述ClassLoader的方法。

    android multithread in c/c++ to call JNI 的第二篇: http://blog.csdn.net/wu4long/article/details/17757433







     

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved