JNI

使用JNI的原則

總之,只有當你必須在同一進程中調用本地代碼時,再使用JNI。

1、JAVA程序和本地程序使用TCP/IP或者IPC進行交互。

2、當用JAVA程序連接本地數據庫時,使用JDBC提供的API。

3、JAVA程序可以使用分佈式對象技術,如JAVA IDL API。

JNIEnv

JNIEnv 概念 : 是一個線程相關的結構體, 該結構體代表了 Java 在本線程的運行環境 ;

JNIEnv 與 JavaVM :

注意區分這兩個概念;

– JavaVM : JavaVM 是 Java虛擬機在 JNI 層的代表, JNI 全局只有一個;

– JNIEnv : JavaVM 在線程中的代表, 每個線程都有一個, JNI 中可能有很多個JNIEnv;

JNIEnv 作用 :

– 調用 Java 函數 : JNIEnv 代表 Java 運行環境, 可以使用 JNIEnv 調用 Java 中的代碼;

– 操作 Java 對象 : Java 對象傳入 JNI 層就是 Jobject 對象, 需要使用 JNIEnv 來操作這個 Java 對象;
JNIEnv 體系結構

線程相關 : JNIEnv 是線程相關的, 即 在 每個線程中 都有一個 JNIEnv 指針, 每個JNIEnv 都是線程專有的, 其它線程不能使用本線程中的 JNIEnv, 線程 A 不能調用 線程 B 的 JNIEnv;

JNI 例子:

  1. Java 層
   private native String printJNI(String inputStr);
  1. 生成文件:com_android_HelloWorld.h

到classes一級目錄:/HelloWorld/bin/classes/

執行如下命令:

  javah com.android.HelloWorld

  生成文件:com_android_HelloWorld.h

  1. 實現JNI原生函數源文件:

新建com_android_HelloWorld.c文件:

定義OnLoad
OnLoadJava_com_android_HelloWorld_printJNI
  1. 編譯生成so庫

      編譯com_android_HelloWorld.c成so庫可以和app一起編譯,也可以都單獨編譯。
      
      

參數轉換

1. 如何將java傳入的String參數轉換爲c的char*,然後使用?

java傳入的String參數,在c文件中被jni轉換爲jstring的數據類型,

//在c文件中聲明
char* test;
test = (char*)(*env)->GetStringUTFChars(env, jstring, NULL);
//注意:test使用完後,通知虛擬機平臺相關代碼無需再訪問:
(*env)->ReleaseStringUTFChars(env, jstring, test);
2.將c中獲取的一個char*的buffer傳遞給java?

這個char*如果是一般的字符串的話,作爲string傳回去就可以了。如果是含有’\0’的buffer,最好作爲bytearray傳出,因爲可以制定copy的length,如果copy到string,可能到’\0’就截斷了。

unsigned char buffer[256];
int i=0;
for(i=0;i<256;i++)
    buffer[i] = i;
//new一個byte數組
jbyteArray array = (*env)->NewByteArray(env,256);
//拷貝
(*env)->SetByteArrayRegion(env, array, 0, 256, buffer);
3. char* 和jstring互轉

GetStringUTFChars

NewStringUTF

JNIEXPORT jstring JNICALL Java_com_explorer_jni_SambaTreeNative_getDetailsBy    
(JNIEnv *env, jobject jobj, jstring pc_server, jstring server_user, jstring server_passwd)    
{    
        const char *pc = env->GetStringUTFChars(pc_server, NULL);    
        const char *user = env->GetStringUTFChars(server_user, NULL);    
        const char *passwd = env->GetStringUTFChars(server_passwd, NULL);    
        const char *details = smbtree::getPara(pc, user, passwd);    
        jstring jDetails = env->NewStringUTF(details);    
        return jDetails;    
}    
4. 傳對象到JNI調用
   jclass stu_cls = env->GetObjectClass(obj_stu); //或得Student類引用 
 jfieldID ageFieldID = env->GetFieldID(stucls,"age","I"); //獲得得Student類的屬性id     
  jfieldID nameFieldID = env->GetFieldID(stucls,"name","Ljava/lang/String;"); // 獲得屬性ID    

  jint age = env->GetIntField(objstu , ageFieldID);  //獲得屬性值    
  jstring name = (jstring)env->GetObjectField(objstu , nameFieldID);//獲得屬性值    

  const char * c_name = env->GetStringUTFChars(name ,NULL);//轉換成 char *    

  string str_name = c_name ;     
  env->ReleaseStringUTFChars(name,c_name); //釋放引用 
5. 回調Java層方法
jstring str = NULL;    

  jclass clz = env->FindClass("cc/androidos/jni/JniTest");    
  //獲取clz的構造函數並生成一個對象    
  jmethodID ctor = env->GetMethodID(clz, "<init>", "()V");    
  jobject obj = env->NewObject(clz, ctor); 
// 如果是數組類型,則在類型前加[,如整形數組int[] intArray,則對應類型爲[I,整形數組String[] strArray對應爲[Ljava/lang/String;    
  jmethodID mid = env->GetMethodID(clz, "sayHelloFromJava", "(Ljava/lang/String;II[I)I");   
 jint javaIndex = env->CallIntMethod(obj, mid, str1, index1, index2, testIntArray);  
Java 類型 本地類型 描述
boolean jboolean C/C++8位整型
byte jbyte C/C++帶符號的8位整型
char jchar C/C++無符號的16位整型 (char 在java中是2個字節。java採用unicode,2個字節(16位)來表示一個字符)
short jshort C/C++帶符號的16位整型
int jint C/C++帶符號的32位整型
long jlong C/C++帶符號的64位整型e
float jfloat C/C++32位浮點型
double jdouble C/C++64位浮點型
Object jobject 任何Java對象,或者沒有對應java類型的對象
Class jclass Class對象
String jstring 字符串對象
Object[] jobjectArray 任何對象的數組
boolean[] jbooleanArray 布爾型數組
byte[] jbyteArray 比特型數組
char[] jcharArray 字符型數組
short[] jshortArray 短整型數組
int[] jintArray 整型數組
long[] jlongArray 長整型數組
float[] jfloatArray 浮點型數組
double[] jdoubleArray 雙浮點型數組
Java 類型 符號
boolean Z
byte B
char C
short S
int I
long J
float F
double D
void V
objects對象 L類名
Arrays數組 [數組類型
methods方法 (參數類型)返回類型
String Ljava/lang/String;
int[ ] [I
float[ ] [F
Object[ ] [Ljava/lang/Object;
int [ ][ ] 其描述符爲[[I
float[ ][ ] 其描述符爲[[F
Java層方法 JNI函數簽名
String test ( ) Ljava/lang/String;
int f (int i, Object object) (ILjava/lang/Object;)I
void set (byte[ ] bytes) ([B)V
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章