JNI之------C调用java接口
来源:互联网 发布:vue.js window.open 编辑:程序博客网 时间:2024/04/28 18:50
主要是分调用java中的static函数和非static函数。
本地activity code:
public class TestJNIActivity extends Activity {private static final String TAG = "TestJNIActivity";static{System.loadLibrary("shift_jni");}TestJNI jni = new TestJNI();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);Button test1 = (Button)findViewById(R.id.test1);test1.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) { test1();}});Button test2 = (Button)findViewById(R.id.test2);test2.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { test2(); } });Button test3 = (Button)findViewById(R.id.test3); test3.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { test3(); } });}private void test1(){ Log.d(TAG, "=====call c method======"+jni.test1());}private void test2(){ Log.d(TAG, "=====c call java static method======"+jni.test2());}private void test3(){ Log.d(TAG, "=====c call java not static method======"); jni.test3();}}
本地java code:
public class TestJNI { private static final String TAG = "TestJNI"; public native int printJNI(); public native int callJavaMethod1(); public native void callJavaMethod2(); /** * java call c method by jni */ public int test1(){ return printJNI(); } public int test2(){ return callJavaMethod1(); } public void test3(){ callJavaMethod2(); } /** * c call java static method by jni */ public static int method1(){ Log.d(TAG, "===method1====="); return 0; } public void method2(String msg){ Log.d(TAG, "===method2===="+msg); }}
native code:
#include <jni.h>#include <assert.h>#include "test_jni.h"#include "c2java.h"/*#include "com_shift_testjni_TestJNI.h"JNIEXPORT jint JNICALL Java_com_shift_testjni_TestJNI_printJNI (JNIEnv *env, jobject obj){ALOGE("====jni test successfully===");return 0;}*/JNIEXPORT jint JNICALL printForTest (JNIEnv *env, jobject obj){LOGD("====printForTest===");return 0;}JNIEXPORT jint JNICALL callStaticMethod (JNIEnv *env, jobject obj){int ret = c_2_static_java(env);LOGD("====callStaticMethod==%d===", ret);return ret;}JNIEXPORT void JNICALL callNonstaticMethod (JNIEnv *env, jobject obj){LOGD("====callNonstaticMethod==%d===", c_2_nonstatic_java(env));}static JNINativeMethod methods[] = { { "printJNI", "()I", (void*)printForTest}, { "callJavaMethod1", "()I", (void*)callStaticMethod}, { "callJavaMethod2", "()V", (void*)callNonstaticMethod}, }; /* * Register methods for one class. */static int registerNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* methods, int numMethods){ int rc; jclass clazz; clazz = (*env)->FindClass(env, className); if (clazz == NULL) { LOGE("Native registration unable to find class '%s'\n", className); return JNI_FALSE; } if (rc = ((*env)->RegisterNatives(env, clazz, methods, numMethods)) < 0) { LOGE("RegisterNatives failed for '%s' %d\n", className, rc); return JNI_FALSE; } return JNI_TRUE;} /* * Register methods for all classes. * * returns JNI_TRUE on success. */static int registerNatives(JNIEnv* env){if (!registerNativeMethods(env, "com/shift/testjni/TestJNI", methods, NELEM(methods))){return JNI_FALSE;}return JNI_TRUE;}/* * Called by the VM when the shared library is loaded. */ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved){JNIEnv* env = NULL;jint result = -1;LOGD("=====JNI_OnLoad=====\n");if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)goto bail;assert(env != NULL);if (!registerNatives(env))goto bail;/* success -- return valid version number */result = JNI_VERSION_1_6; bail: LOGE("Leaving JNI_OnLoad (result=0x%x)\n", result); return result;}之前的code都是很ok的,之前Android基础总结之九:JNI详解已经有过介绍。
但是实现部分的code在书写调试过程中出现了问题:
#include <jni.h>#include "c2java.h"#include "test_jni.h"jclass TestJNI;jobject mTestJNI;jmethodID c2static;jmethodID c2nonstatic;int init(JNIEnv *env){LOGD("====init=====");if(TestJNI == NULL){TestJNI = (*env)->FindClass(env, "com/shift/testjni/TestJNI");if(TestJNI == NULL)return -1;}if(mTestJNI == NULL){if(getInstance(env) != 1){(*env)->DeleteLocalRef(env, TestJNI);return -2;}}if(c2static == NULL){c2static = (*env)->GetStaticMethodID(env, TestJNI, "method1", "()I");if(c2static == NULL){(*env)->DeleteLocalRef(env, TestJNI);(*env)->DeleteLocalRef(env, mTestJNI);return -3;}}if(c2nonstatic ==NULL){c2nonstatic = (*env)->GetMethodID(env, TestJNI, "method2", "(Ljava/lang/String;)V");if(c2nonstatic == NULL){(*env)->DeleteLocalRef(env, TestJNI);(*env)->DeleteLocalRef(env, mTestJNI);(*env)->DeleteLocalRef(env, c2static);return -4;}}return JNI_OK;}int getInstance(JNIEnv *env){LOGD("====getInstance====");jmethodID id = (*env)->GetMethodID(env, TestJNI, "<init>", "()V");//默认构造函数,不传参数if(id == 0)return -1;mTestJNI = (*env)->NewObject(env, TestJNI, id);//通过NewObject来创建对象if(mTestJNI == NULL)return -2;return 1;}int c_2_static_java(JNIEnv *env){int result = -1;if(env == NULL){return result;}if(TestJNI==NULL || c2static==NULL){result = init(env);if(result != JNI_OK)return result;}jint java_ret = (*env)->CallStaticIntMethod(env, TestJNI, c2static);//CallStatic***Method,关键字static,***代表返回类型LOGD("==c_2_static_java==%d=", java_ret);return JNI_OK;}int c_2_nonstatic_java(JNIEnv *env){int result = -1;if(env == NULL){return result;}if(TestJNI==NULL || mTestJNI==NULL || c2nonstatic==NULL){result = init(env);if(result != JNI_OK)return result;}jstring jstrMSG = NULL;jstrMSG =(*env)->NewStringUTF(env, "I'm From C");(*env)->CallVoidMethod(env, mTestJNI, c2nonstatic, jstrMSG);//Call***Method,***代表返回类型(*env)->DeleteLocalRef(env, jstrMSG);return JNI_OK;}
c2java中如果这样写的话,会出现一个问题,第一次调用java函数时是ok的,但是第二次调用就会出现:
05-20 07:01:50.048: D/Shift_Test_JNI(13050): ====printForTest===05-20 07:01:50.048: D/TestJNIActivity(13050): =====call c method======005-20 07:01:50.958: D/Shift_Test_JNI(13050): ====init=====05-20 07:01:50.978: D/Shift_Test_JNI(13050): ====getInstance====05-20 07:01:50.978: D/TestJNI(13050): ===method1=====05-20 07:01:50.978: D/Shift_Test_JNI(13050): ==c_2_static_java==0=05-20 07:01:50.978: D/Shift_Test_JNI(13050): ====callStaticMethod==0===05-20 07:01:50.978: D/TestJNIActivity(13050): =====c call java static method======005-20 07:01:54.568: E/dalvikvm(13050): JNI ERROR (app bug): accessed stale local reference 0xd7d0001d (index 7 in a table of size 7)05-20 07:01:54.568: W/dalvikvm(13050): JNI WARNING: jclass is an invalid local reference (0xd7d0001d) (CallStaticIntMethod)05-20 07:01:54.568: W/dalvikvm(13050): in Lcom/shift/testjni/TestJNI;.callJavaMethod1:()I (CallStaticIntMethod)05-20 07:01:54.578: I/dalvikvm(13050): "main" prio=5 tid=1 RUNNABLE05-20 07:01:54.578: I/dalvikvm(13050): | group="main" sCount=0 dsCount=0 obj=0xb3b03ca8 self=0xb8e0c39805-20 07:01:54.578: I/dalvikvm(13050): | sysTid=13050 nice=0 sched=0/0 cgrp=apps handle=-122481015605-20 07:01:54.578: I/dalvikvm(13050): | state=R schedstat=( 960000000 1800000000 263 ) utm=65 stm=31 core=005-20 07:01:54.578: I/dalvikvm(13050): at com.shift.testjni.TestJNI.callJavaMethod1(Native Method)05-20 07:01:54.618: I/dalvikvm(13050): at com.shift.testjni.TestJNI.test2(TestJNI.java:19)05-20 07:01:54.618: I/dalvikvm(13050): at com.shift.testjni.TestJNIActivity.test2(TestJNIActivity.java:53)05-20 07:01:54.618: I/dalvikvm(13050): at com.shift.testjni.TestJNIActivity.access$1(TestJNIActivity.java:52)05-20 07:01:54.618: I/dalvikvm(13050): at com.shift.testjni.TestJNIActivity$2.onClick(TestJNIActivity.java:34)05-20 07:01:54.618: I/dalvikvm(13050): at android.view.View.performClick(View.java:4438)05-20 07:01:54.618: I/dalvikvm(13050): at android.view.View$PerformClick.run(View.java:18422)05-20 07:01:54.618: I/dalvikvm(13050): at android.os.Handler.handleCallback(Handler.java:733)05-20 07:01:54.628: I/dalvikvm(13050): at android.os.Handler.dispatchMessage(Handler.java:95)05-20 07:01:54.628: I/dalvikvm(13050): at android.os.Looper.loop(Looper.java:136)05-20 07:01:54.628: I/dalvikvm(13050): at android.app.ActivityThread.main(ActivityThread.java:5017)05-20 07:01:54.628: I/dalvikvm(13050): at java.lang.reflect.Method.invokeNative(Native Method)05-20 07:01:54.628: I/dalvikvm(13050): at java.lang.reflect.Method.invoke(Method.java:515)05-20 07:01:54.628: I/dalvikvm(13050): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)05-20 07:01:54.628: I/dalvikvm(13050): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)05-20 07:01:54.628: I/dalvikvm(13050): at dalvik.system.NativeStart.main(Native Method)05-20 07:01:54.628: E/dalvikvm(13050): VM aborting05-20 07:01:54.648: A/libc(13050): Fatal signal 6 (SIGABRT) at 0x000032fa (code=-6), thread 13050 (m.shift.testjni)后来查了很多资料,才弄清楚,在c返回java的时候LocalRef都会释放。这样导致了指针的游离,下一次使用就不行了。
后来只能采用GlobalRef,试验证明这样做是ok的。
code如下:
#include <jni.h>#include <stdio.h>#include <string.h>#ifndef _C_TO_JAVA_H_#define _C_TO_JAVA_H_struct fields_t {jclass TestJNI;jobject mTestJNI; jmethodID c2static; jmethodID c2nonstatic;};int c_2_static_java(JNIEnv *env);int c_2_nonstatic_java(JNIEnv *env);#endif
#include <jni.h>#include "c2java.h"#include "test_jni.h"static struct fields_t fields;int getInstance(JNIEnv *env){LOGD("====getInstance====");jmethodID id = (*env)->GetMethodID(env, fields.TestJNI, "<init>", "()V");if(id == 0)return -1;jobject temp = (*env)->NewObject(env, fields.TestJNI, id);if(temp == NULL)return -2;fields.mTestJNI = (*env)->NewGlobalRef(env, temp);(*env)->DeleteLocalRef(env, temp);return 1;}int native_init(JNIEnv *env){LOGD("====init=====");if(fields.TestJNI == NULL){jclass temp = (*env)->FindClass(env, "com/shift/testjni/TestJNI");if(temp == NULL)return -1;fields.TestJNI = (jclass)(*env)->NewGlobalRef(env, temp);(*env)->DeleteLocalRef(env, temp);}if(fields.mTestJNI == NULL){if(getInstance(env) != 1){(*env)->DeleteGlobalRef(env, fields.TestJNI);return -2;}}if(fields.c2static == NULL){fields.c2static = (*env)->GetStaticMethodID(env, fields.TestJNI, "method1", "()I");if(fields.c2static == NULL){(*env)->DeleteGlobalRef(env, fields.TestJNI);(*env)->DeleteGlobalRef(env, fields.mTestJNI);return -3;}}if(fields.c2nonstatic ==NULL){fields.c2nonstatic = (*env)->GetMethodID(env, fields.TestJNI, "method2", "(Ljava/lang/String;)V");if(fields.c2nonstatic == NULL){(*env)->DeleteGlobalRef(env, fields.TestJNI);(*env)->DeleteGlobalRef(env, fields.mTestJNI);(*env)->DeleteLocalRef(env, fields.c2static);return -4;}}return JNI_OK;}int c_2_static_java(JNIEnv *env){int result = -1;if(env == NULL){return result;}if(fields.TestJNI==NULL || fields.c2static==NULL){result = native_init(env);if(result != JNI_OK)return result;}jint java_ret = (*env)->CallStaticIntMethod(env, fields.TestJNI, fields.c2static);LOGD("==c_2_static_java==%d=", java_ret);return JNI_OK;}int c_2_nonstatic_java(JNIEnv *env){int result = -1;if(env == NULL){return result;}if(fields.TestJNI==NULL || fields.mTestJNI==NULL || fields.c2nonstatic==NULL){result = native_init(env);if(result != JNI_OK)return result;}jstring jstrMSG = NULL;jstrMSG =(*env)->NewStringUTF(env, "I'm From C");(*env)->CallVoidMethod(env, fields.mTestJNI, fields.c2nonstatic, jstrMSG);(*env)->DeleteLocalRef(env, jstrMSG);return JNI_OK;}
注意:
1. jmethodID id = (*env)->GetMethodID(env, TestJNI, "<init>", "()V");//默认构造函数,不传参数
2. mTestJNI = (*env)->NewObject(env, TestJNI, id);//通过NewObject来创建对象
3. jint java_ret = (*env)->CallStaticIntMethod(env, TestJNI, c2static);//CallStatic***Method,关键字static,***代表返回类型
4. (*env)->CallVoidMethod(env, mTestJNI, c2nonstatic, jstrMSG);//Call***Method,***代表返回类型
5. 前面的几个函数中都会涉及到变量env,而env是java调用c函数时的第一个参数,这意味着c调用java函数只能在java调用c函数中进行,否则无法获取env变量。也就是说c是不能主动调用java函数的。
参考文献:
http://www.ibm.com/developerworks/cn/java/j-lo-jnileak/index.html?ca=drs-
- JNI之------C调用java接口
- Java调用本地接口jni与C通信----------------JNI
- linux jni 之 java 调用c c++
- JNI之c调用java全面解析
- Java调用C JNI
- jni c调用java
- JNI java c 调用
- JNI C调用Java
- JNI调用java的接口
- JNI调用java接口函数
- android开发教程(十三)——JAVA基础之理解JNI原理(java调用C语言接口)
- 转战Android之NDK(jni, java调用c/c++)
- Android之NDK(jni, java调用c/c++)
- JNI 之c/c++和Java交互,调用java成员
- 【程序员一枚】JNI之Java调用C++(一)
- 转战Android之NDK(jni, c/c++调用java)
- JNI 之二 :java & c/c++ 相互通信及调用
- JNI 之二 :java & c/c++ 相互通信及调用
- 他认为共和热啊地方二概
- 从Maven仓库中导出jar包
- Hiren’s BootCD 15.2下载 – 史上最强大的WinPE U盘启动工具详细介绍
- Linux下chkconfig命令详解
- AGP驱动学习记录
- JNI之------C调用java接口
- 数据库的实用SQL小技巧
- 从ASP.NET的PHP执行速度比较谈起
- java.lang.OutOfMemoryError: PermGen space及其解决方法
- oracle编码转换:AL32UTF8->ZHS16GBK
- eclipse背景颜色更改
- Linux网络编程必看书籍推荐
- 没有找到加密狗
- 广州考试评测系统定制开发