android JNI 提供了很强大的支持,不仅可以采用基本类型做为参数和返回值,同时也支持自定义对象做为参数和返回值,以下举例说明。
一、定义作为输入和返回的自定义类 (仅提供两个简单类型和一个打印函数)
package com.example.jniexample;
import android.util.Log;
public class JNIParam {
public int mInt;
public String mString;
JNIParam(){
mInt = 0;
mString = "0";
}
public void print(String tag){
Log.d(tag, String.format("print: mInt=%d, mString=%s", mInt, mString));
}
}
二. 定义和JNI通信的java封装
功能:测试输入参数和返回值都为自定义对象的本地方法,同时提供必要的调试打印
package com.example.jniexample;
public class JNIParamTest {
private final String TAG = "JNIParamTest";
static {
System.loadLibrary("JNIParamTest");
};
public void runParamTest(){
JNIParam paramIn = new JNIParam();
paramIn.print(TAG);
JNIParam paramOut = doTest(paramIn);
if( paramOut != null ) paramOut.print(TAG);
}
//JNI
private native JNIParam doTest(JNIParam paramIn);
}
三、实现JNI的本地实现
a. 头文件 (JNIParamTest.h)
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_jniexample_JNIParamTest */
#ifndef _Included_com_example_jniexample_JNIParamTest
#define _Included_com_example_jniexample_JNIParamTest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_jniexample_JNIParamTest
* Method: doTest
* Signature: (Lcom/example/jniexample/JNIParam;)Lcom/example/jniexample/JNIParam;
*/
JNIEXPORT jobject JNICALL Java_com_example_jniexample_JNIParamTest_doTest
(JNIEnv *, jobject, jobject);
#ifdef __cplusplus
}
#endif
#endif
b. c文件 (JNIParamTest.c)
#include "JNIParamTest.h"
#include "android/log.h"
#define TAG "JNI_ParamTest"
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
/*
* Class: com_example_jniexample_JNIParamTest
* Method: doTest
* Signature: (Lcom/example/jniexample/JNIParam;)Lcom/example/jniexample/JNIParam;
*/
JNIEXPORT jobject JNICALL Java_com_example_jniexample_JNIParamTest_doTest
(JNIEnv *env, jobject thiz, jobject paramIn)
{
jclass paramInClass = (*env)->GetObjectClass(env, paramIn);
if( paramInClass){
jboolean iscopy;
jfieldID intId = (*env)->GetFieldID(env, paramInClass, "mInt", "I");
jint num = (int)(*env)->GetIntField(env, paramIn, intId);
LOGD("num = %d", num);
jfieldID strId = (*env)->GetFieldID(env, paramInClass, "mString", "Ljava/lang/String;");
jstring str = (jstring)(*env)->GetObjectField(env, paramIn, strId);
const char *locstr = (*env)->GetStringUTFChars(env, str, &iscopy);
LOGD("str = %s", locstr);
(*env)->ReleaseStringUTFChars(env, str, locstr);
}
jclass cls = (*env)->FindClass(env, "com/example/jniexample/JNIParam");
jmethodID id = (*env)->GetMethodID(env, cls, "<init>", "()V");
jobject paramOut = (*env)->NewObjectA(env, cls, id, 0);
jfieldID intId = (*env)->GetFieldID(env, cls, "mInt", "I");
(*env)->SetIntField(env, paramOut, intId, 1);
jfieldID strId = (*env)->GetFieldID(env, cls, "mString", "Ljava/lang/String;");
(*env)->SetObjectField(env, paramOut, strId, (jstring)(*env)->NewStringUTF(env, "1"));
return paramOut;
}
四、提供一个测试环境
package com.example.jniexample;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class JNIExample extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_jniexample);
JNIParamTest test = new JNIParamTest();
test.runParamTest();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_jniexample, menu);
return true;
}
}
实现了一个Activity, 启动就调用
五、测试结果: (logcat 查看)
D/JNIParamTest( 6135): print: mInt=0, mString=0
D/JNI_ParamTest( 6135): num = 0
D/JNI_ParamTest( 6135): str = 0
D/JNIParamTest( 6135): print: mInt=1, mString=1
六、其他类型转换可以参考: