前面介绍了JNI的基本规范以及JNI的接口的生成过程。本文通过一个jni_test 应用实践操作JNI的接口各种典型应用。
jni_test从jni的字符串,数组,基本类型,自定义类,C回调java静态方法,C回调Java的实例方法,C访问Java的静态变量,C访问Java的实例变量,Java传内存数据给C,C传内存数据给Java 共10个demo演示jni各种典型应用场景。
一、UI设计
通过修改active_main.xml(为了简单起见采用相对布局),或者直接使用design工具拖动布局(先拖一个layout线下布局,再在该布局上排上控件,类似MFC的UI设计原理),UI效果如下。
jni_test的UI界面
二、JIN接口的定义
Java JNI接口声明如下:
- public native String stringFromJNI(String src);
- public native String CallbackFuncTest();
- public native int CallbackClassTest();
- public native int CallbackStaticVarTest();
- public native int CallbackVarTest(TestNative obj);
- public native int add(int x,int y);
- public native int [] updateArray(int [] src,int len);
- public native void passmem2C(int [] src,int len);
- public native int [] getmem2C();
三、在native层jni实现如下:
- extern "C" JNIEXPORT jstring JNICALL
- Java_com_example_jni_1test_MainActivity_stringFromJNI(
- JNIEnv* env,
- jobject /* this */,
- jstring src) {
- std::string hello = "Hello3 from C++";
- const char* native_string = env->GetStringUTFChars(src, NULL);
- std::string temp(native_string);
- std::string dst = hello+temp;
- env->ReleaseStringUTFChars(src, native_string);
- return env->NewStringUTF(dst.c_str());
- }
- //回调java 静态的方法
- extern "C" JNIEXPORT jstring Java_com_example_jni_1test_MainActivity_CallbackFuncTest(
- JNIEnv* env,
- jobject /* this */ ){
- jclass mJclass;
- jstring mJstring;
- jmethodID mJStaticmethodID;
- //1.从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象
- int i = 0;
- mJclass = env->FindClass("com/example/jni_test/TestNative"); //JNIEnv*, const char*
- if (mJclass == NULL) {
- LOGI("test","callJavaStaticMethod==>>mJclass==NULL==>>%s", "");
- return env->NewStringUTF("CallbackTest is failed");
- }
- // 2、从clazz类中查找callStaticMethod方法
- mJStaticmethodID = env->GetStaticMethodID(mJclass,
- "settext",
- "(Ljava/lang/String;)V"); //JNIEnv*, jclass, const char*, const char*
- if (mJStaticmethodID == NULL) {
- LOGI("test","=====>>>can not foud callStaticMethod");
- return env->NewStringUTF("CallbackFuncTest is failed");
- }
- mJstring= env->NewStringUTF("settext is now");
- env->CallStaticVoidMethod(mJclass, mJStaticmethodID, mJstring);
- // 删除局部引用
- env->DeleteLocalRef(mJstring);
- env->DeleteLocalRef(mJclass);
- return env->NewStringUTF("CallbackFuncTest is now");
-
- }
- //回调java中的类
- extern "C" JNIEXPORT jint Java_com_example_jni_1test_MainActivity_CallbackClassTest(
- JNIEnv* env,
- jobject /* this */ ) {
- jclass mJclass = NULL;
- jmethodID jmethodID_Construct; //构造方法ID
- jmethodID jmethodID_Method_Instance; //方法的ID
- jmethodID jmethodID_Method_Instance2; //方法的ID
- jobject jobjectMyClass; //类的实例
- //1、从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象
- mJclass = env->FindClass("com/example/jni_test/TestNative");
- if (mJclass == NULL) {
- printf("====FindClass not found \n");
- return 0;
- }
- // 2、获取类的默认构造方法ID
- jmethodID_Construct = env->GetMethodID(mJclass, "<init>", "(I)V");
- if (jmethodID_Construct == NULL) {
- printf("GetMethodID not found ==>>jmethodID_Construct");
- return 0;
- }
- // 3、查找实例方法的ID
- jmethodID_Method_Instance = env->GetMethodID(mJclass,
- "setnum", "(I)V");
- if (jmethodID_Method_Instance == NULL) {
- return 0;
- }
- // 4、创建该类的实例 调用无参构造方法 如果其它构造方法,后面可传参数
- jobjectMyClass = env->NewObject(mJclass, jmethodID_Construct,100); //JNIEnv*, jclass, jmethodID, ...
- if (jobjectMyClass == NULL) {
- return 0;
- }
- // 5、调用对象的实例方法
-
- env->CallVoidMethod(jobjectMyClass, jmethodID_Method_Instance,
- 100); //JNIEnv*, jobject, jmethodID, ...
- // 3、查找实例方法的ID
- jmethodID_Method_Instance2 = env->GetMethodID(mJclass,
- "getnum", "()I");
- if (jmethodID_Method_Instance2 == NULL) {
- return 0;
- }
- int ret;
- ret=env->CallIntMethod(jobjectMyClass, jmethodID_Method_Instance2); //JNIEnv*, jobject, jmethodID, ...
-
- // 删除局部引用
- env->DeleteLocalRef(jobjectMyClass);
- return ret;
- }
- //回调java中的类中静态变量
- extern "C" JNIEXPORT jint Java_com_example_jni_1test_MainActivity_CallbackStaticVarTest(
- JNIEnv* env,
- jobject /* this */ ) {
- jclass clazz;
- jfieldID fid;
- int test;
-
- //1.获取ClassField类的Class引用
- clazz = env->FindClass("com/example/jni_test/TestNative");
- if (clazz == NULL) { // 错误处理
- return 0;
- }
- //2.获取ClassField类静态变量test的属性ID
- fid = env->GetStaticFieldID(clazz, "iVar", "I");
- if (fid == NULL) {
- return 0;
- }
-
- // 3.获取静态变量test的值
-
-
- test = env->GetStaticIntField(
- clazz,
- fid);
- LOGI("test","test = %d\n", test);
- // 4.修改静态变量num的值
- jint ret = 55;
- env->SetStaticIntField(clazz, fid, ret);
- test = env->GetStaticIntField(
- clazz,
- fid);
- // 删除属部引用
- env->DeleteLocalRef(clazz);
- return test;
- }
- extern "C" JNIEXPORT int Java_com_example_jni_1test_MainActivity_CallbackVarTest(
- JNIEnv* env,
- jobject /* this */,jobject obj) {
- jclass clazz;
- jfieldID fid;
- jstring j_str;
- jstring j_newStr;
- const char *c_str = NULL;
- // 1.获取AccessField类的Class引用
- clazz = env->GetObjectClass(obj);
- if (clazz == NULL) {
- return 0;
- }
- // 2. 获取AccessField类实例变量str的属性ID
- fid = env->GetFieldID(clazz, "str", "Ljava/lang/String;");
- if (clazz == NULL) {
- return 0;
- }
- // 3. 获取实例变量str的值
- j_str = static_cast<jstring>(env->GetObjectField(obj, fid)); //JNIEnv*, jobject, jfieldID
- if (j_str == NULL) {
- return 0;
- }
- // 4. 将unicode编码的java字符串转换成C风格字符串
- c_str = env->GetStringUTFChars(j_str, NULL); //JNIEnv*, jstring, jboolean*
- if (c_str == NULL) {
- return 0;
- }
- LOGI("test","In C--->ClassField.str = %s\n", c_str);
- env->ReleaseStringUTFChars(j_str, c_str); //JNIEnv*, jstring, const char*
- // 5. 修改实例变量str的值
- j_newStr = env->NewStringUTF("This is new String");
- if (j_newStr == NULL) {
- return 0;
- }
- env->SetObjectField(obj, fid, j_newStr); //JNIEnv*, jobject, jfieldID, jobject
-
- // 6.删除局部引用
- env->DeleteLocalRef(clazz); //JNIEnv*, jobject
- env->DeleteLocalRef(j_str); //JNIEnv*, jobject
- env->DeleteLocalRef(j_newStr); //JNIEnv*, jobject
- //env->DeleteLocalRef(env,fid);//JNIEnv*, jobject 返回的非object,不能使用 DeleteLocalRef
- //使用NewObject就会返回创建出来的实例的局部引用 可 DeleteLocalRef
- return 1;
- }
-
- extern "C" JNIEXPORT jint JNICALL Java_com_example_jni_1test_MainActivity_add
- (JNIEnv *env, jobject, jint x, jint y){
- int x1 = x;
- int y1 = y;
- int sum = (x1+y1)*200;
- __android_log_print(ANDROID_LOG_DEBUG,"test","hello5 world");
- LOGD("test","hello sum is %d",sum);
- //printf("hello3 world");
- // std::cout<<"hello4 world"<<std::endl;
- return sum;
- }
- extern "C" JNIEXPORT jintArray JNICALL Java_com_example_jni_1test_MainActivity_updateArray
- (JNIEnv *env, jobject, jintArray src,jint len)
- {
- jintArray dst;
- jint *cPArray = env->GetIntArrayElements(src, NULL);
- if (cPArray == NULL) {
- return 0; // JVM复制原始数据到缓冲区失败
- }
- // jint i;
- for(int i=0;i<len;i++)
- {
- cPArray[i]=cPArray[i]+100;
- LOGD("test","cPArray %d",cPArray[i]);
- }
- //给java层返回数组方式1
- int cInts[len]; //定义一个数组
- for (int i = 0; i < len; i++) {
- cInts[i] = cPArray[i];
- }
- dst = env->NewIntArray(len);
- if (dst == NULL) {
- return NULL; /* out of memory error thrown */
- }
- //move from the temp structure to the java structure 将native数组转换为java层数组
- env->SetIntArrayRegion(dst, 0, sizeof(cInts) / sizeof(cInts[0]),
- cInts);
- env->ReleaseIntArrayElements(src, cPArray, 0); // 释放可能复制的缓冲区
- return dst;
- }
- extern "C" JNIEXPORT void JNICALL Java_com_example_jni_1test_MainActivity_passmem2C
- (JNIEnv *env, jobject, jintArray src,jint len) {
-
- jintArray dst;
- int *cPArray = env->GetIntArrayElements(src, NULL);
- if (cPArray == NULL) {
- return ; // JVM复制原始数据到缓冲区失败
- }
- for(int i=0;i<len;i++)
- {
- *(cPArray+i)=i;
- LOGD("test","cPArray %d", *(cPArray+i));
- }
- env->ReleaseIntArrayElements(src, cPArray, 0); // 释放可能复制的缓冲区
- }
- extern "C" JNIEXPORT jintArray JNICALL Java_com_example_jni_1test_MainActivity_getmem2C
- (JNIEnv *env, jobject){
- jintArray dst;
- int *p = (int *)malloc(10);
- if(!p)
- {
- LOGD("test","malloc is failed");
- }
- for(int i=0;i<10;i++)
- {
- *(p+i)=i;
- LOGD("test","navtive cPArray %d", *(p+i));
- }
- dst = env->NewIntArray(10);
- if (dst == NULL) {
- return NULL; /* out of memory error thrown */
- }
- //move from the temp structure to the java structure 将native数组转换为java层数组
- env->SetIntArrayRegion(dst, 0, 10,p);
- return dst;
- }
-