Android JNI 自定义对象为参数和返回值


Android JNI 提供了很强大的支持,不仅可以采用基本类型做为参数和返回值,同时也支持自定义对象做为参数和返回值,以下举例说明。

一、定义作为输入和返回的自定义类 (仅提供两个简单类型和一个打印函数)

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

二. 定义和JNI通信的java封装 

功能:测试输入参数和返回值都为自定义对象的本地方法,同时提供必要的调试打印

  1. package com.example.jniexample; 
  2.  
  3. public class JNIParamTest { 
  4.     private final String TAG = "JNIParamTest"
  5.      
  6.     static { 
  7.         System.loadLibrary("JNIParamTest"); 
  8.     }; 
  9.  
  10.     public void runParamTest(){ 
  11.         JNIParam paramIn = new JNIParam(); 
  12.         paramIn.print(TAG); 
  13.          
  14.         JNIParam paramOut = doTest(paramIn); 
  15.         if( paramOut != null ) paramOut.print(TAG); 
  16.     } 
  17.      
  18.     //JNI  
  19.     private native JNIParam doTest(JNIParam paramIn); 

三、实现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.  
  5. #ifndef _Included_com_example_jniexample_JNIParamTest  
  6. #define _Included_com_example_jniexample_JNIParamTest  
  7. #ifdef __cplusplus  
  8. extern "C" { 
  9. #endif  
  10. /* 
  11.  * Class:     com_example_jniexample_JNIParamTest 
  12.  * Method:    doTest 
  13.  * Signature: (Lcom/example/jniexample/JNIParam;)Lcom/example/jniexample/JNIParam; 
  14.  */ 
  15. JNIEXPORT jobject JNICALL Java_com_example_jniexample_JNIParamTest_doTest 
  16.   (JNIEnv *, jobject, jobject); 
  17.  
  18. #ifdef __cplusplus  
  19. #endif  
  20. #endif 

b. c文件 (JNIParamTest.c)

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

四、提供一个测试环境

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

实现了一个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 

六、其他类型转换可以参考:

相关内容