1. 程式人生 > >jni 自定義物件為引數和返回值

jni 自定義物件為引數和返回值

 android JNI 提供了很強大的支援,不僅可以採用基本型別做為引數和返回值,同時也支援自定義物件做為引數和返回值,以下舉例說明。

一、定義作為輸入和返回的自定義類 (僅提供兩個簡單型別和一個列印函式)

  1. package com.example.jniexample;  
  2. import android.util.Log;  
  3. publicclass JNIParam {  
  4.     publicint mInt;  
  5.     public String mString;  
  6.     JNIParam(){  
  7.         mInt    = 0;  
  8.         mString = "0"
    ;   
  9.     }  
  10.     publicvoid print(String tag){  
  11.         Log.d(tag, String.format("print: mInt=%d, mString=%s", mInt, mString));  
  12.     }  
  13. }  

二. 定義和JNI通訊的java封裝 

功能:測試輸入引數和返回值都為自定義物件的本地方法,同時提供必要的除錯列印

  1. package com.example.jniexample;  
  2. publicclass JNIParamTest {  
  3.     privatefinal String TAG = 
    "JNIParamTest";  
  4.     static {  
  5.         System.loadLibrary("JNIParamTest");  
  6.     };  
  7.     publicvoid runParamTest(){  
  8.         JNIParam paramIn = new JNIParam();  
  9.         paramIn.print(TAG);  
  10.         JNIParam paramOut = doTest(paramIn);  
  11.         if( paramOut != null ) paramOut.print(TAG);  
  12.     }  
  13.     //JNI
  14.     privatenative JNIParam doTest(JNIParam paramIn);  
  15. }  

三、實現JNI的本地實現

a. 標頭檔案 (JNIParamTest.h)

  1. /* DO NOT EDIT THIS FILE - it is machine generated */
  2. #include <jni.h>
  3. /* Header for class com_example_jniexample_JNIParamTest */
  4. #ifndef _Included_com_example_jniexample_JNIParamTest
  5. #define _Included_com_example_jniexample_JNIParamTest
  6. #ifdef __cplusplus
  7. extern"C" {  
  8. #endif
  9. /* 
  10.  * Class:     com_example_jniexample_JNIParamTest 
  11.  * Method:    doTest 
  12.  * Signature: (Lcom/example/jniexample/JNIParam;)Lcom/example/jniexample/JNIParam; 
  13.  */
  14. JNIEXPORT jobject JNICALL Java_com_example_jniexample_JNIParamTest_doTest  
  15.   (JNIEnv *, jobject, jobject);  
  16. #ifdef __cplusplus
  17. }  
  18. #endif
  19. #endif

b. c檔案 (JNIParamTest.c)
  1. #include "JNIParamTest.h"
  2. #include "android/log.h"
  3. #define TAG  "JNI_ParamTest"
  4. #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
  5. /* 
  6.  * Class:     com_example_jniexample_JNIParamTest 
  7.  * Method:    doTest 
  8.  * Signature: (Lcom/example/jniexample/JNIParam;)Lcom/example/jniexample/JNIParam; 
  9.  */
  10. JNIEXPORT jobject JNICALL Java_com_example_jniexample_JNIParamTest_doTest  
  11.   (JNIEnv *env, jobject thiz, jobject paramIn)  
  12. {  
  13.     jclass paramInClass = (*env)->GetObjectClass(env, paramIn);  
  14.     if( paramInClass){  
  15.         jboolean iscopy;  
  16.         jfieldID intId = (*env)->GetFieldID(env, paramInClass, "mInt""I");  
  17.         jint num = (int)(*env)->GetIntField(env, paramIn, intId);  
  18.         LOGD("num = %d", num);  
  19.         jfieldID strId = (*env)->GetFieldID(env, paramInClass, "mString""Ljava/lang/String;");  
  20.         jstring str = (jstring)(*env)->GetObjectField(env, paramIn, strId);  
  21.         constchar *locstr = (*env)->GetStringUTFChars(env, str, &iscopy);  
  22.         LOGD("str = %s", locstr);  
  23.         (*env)->ReleaseStringUTFChars(env, str, locstr);  
  24.     }  
  25.     jclass cls = (*env)->FindClass(env, "com/example/jniexample/JNIParam");  
  26.     jmethodID id = (*env)->GetMethodID(env, cls, "<init>""()V");  
  27.     jobject paramOut = (*env)->NewObjectA(env, cls, id, 0);  
  28.     jfieldID  intId = (*env)->GetFieldID(env, cls, "mInt""I");  
  29.     (*env)->SetIntField(env, paramOut, intId, 1);  
  30.     jfieldID  strId = (*env)->GetFieldID(env, cls, "mString""Ljava/lang/String;");  
  31.     (*env)->SetObjectField(env, paramOut, strId, (jstring)(*env)->NewStringUTF(env, "1"));  
  32.     return paramOut;  
  33. }  


四、提供一個測試環境

  1. package com.example.jniexample;  
  2. import android.os.Bundle;  
  3. import android.app.Activity;  
  4. import android.view.Menu;  
  5. publicclass JNIExample extends Activity {  
  6.     @Override
  7.     publicvoid onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.activity_jniexample);  
  10.         JNIParamTest test = new JNIParamTest();  
  11.         test.runParamTest();  
  12.     }  
  13.     @Override
  14.     publicboolean onCreateOptionsMenu(Menu menu) {  
  15.         getMenuInflater().inflate(R.menu.activity_jniexample, menu);  
  16.         returntrue;  
  17.     }  
  18. }  

實現了一個Activity, 啟動就呼叫

五、測試結果: (logcat 檢視)

  1. D/JNIParamTest( 6135): print: mInt=0, mString=0
  2. D/JNI_ParamTest( 6135): num = 0
  3. D/JNI_ParamTest( 6135): str = 0
  4. D/JNIParamTest( 6135): print: mInt=1, mString=1


六、其他型別轉換可以參考: