C本地接口
JNIEnv* jniEnv = NULL;
jclass TestProvider = NULL;
jobject mTestProvider = NULL;
void CtoJavaInit(void){
TestProvider = (*jniEnv)->FindClass(jniEnv,"com/example/jni/C2jni");
if(NULL == TestProvider)return 2;
jmethodID construction_id = (*jniEnv)->GetMethodID(jniEnv, TestProvider, "<init>", "()V");
if(0 == construction_id)return 3;
mTestProvider = (*jniEnv)->NewObject(jniEnv, TestProvider, construction_id);
if(NULL == mTestProvider)return 4;
SendJ = (*jniEnv)->GetMethodID(jniEnv, TestProvider, "javaSend","([BI)I");
if(NULL == obdSendJ)return 5;
return 0;
}
int cSend(char *data, int datalen){
int len,intresult;
jbyteArray bytes;
if(NULL == jniEnv || NULL == mTestProvider || NULL == obdSendJ)return 0;
if(NULL == data || datalen > 128)return 0;
bytes = (*jniEnv)->NewByteArray(jniEnv, datalen);
if(NULL == bytes)return 0;
(*jniEnv)->SetByteArrayRegion(jniEnv, bytes, 0, datalen, (const jbyte *)data);
(*jniEnv)->CallIntMethod(jniEnv, mTestProvider, obdSendJ, bytes, datalen);
(*jniEnv)->DeleteLocalRef(jniEnv, bytes);
return datalen;
}
JNIEXPORT void JNICALL
Java_nativeMethod(JNIEnv *env, jobject obj){
char *sendtest = "test...";
jniEnv = env;
CtoJavaInit();
cSend(sendtest, strlen(sendtest);
}
说明:
JAVA代码循环调用nativeMethod接口,nativeMethod则通过cSend将一串数据发送到java的javaSend接口
问题是:循环发送N次后(200次左右)(*jniEnv)->CallIntMethod(jniEnv, mTestProvider, obdSendJ, bytes, datalen);出现崩溃
也做过以下测试:
nativeMethod接口中做如下修改
char *sendtest = "test...";
jniEnv = env;
if(nativeMethod_firstcall == 1)CtoJavaInit(); //只在首次调用nativeMethod才进行接口初始化
cSend(sendtest, strlen(sendtest);
但结果是软件更快崩溃也试过在每次nativeMethod返回时释放mTestProvider,但依然没有效果
请大牛们指点 ...
测试了一上午发现原来不是C调用java接口出了问题,而是在java调用C接口时出问题,如下C接口
int Java_com_example_jni_jni_jniRead( JNIEnv* env, jobject obj, jbyteArray data, jint datalen){
jbyte *s8data;
s8data = (*env)->GetByteArrayElements(env,data,0);
//以下两句存在不存在都一个样
(*env)->DeleteLocalRef(env, s8data);
s8data = NULL;
return 0;
}
就这么个简单接口调用N(大概900多次)就崩溃,屏蔽GetByteArrayElements
正常,请教是什么原因呢,该如何修改??
GetByteArrayElements之后是需要ReleaseByteArrayElements的
至于主贴中的问题,个人猜想还是因为那个init中NewObject导致局部引用表溢出崩溃的首先保证这个方法真的只调用一次(可以通过在init中输出LOG查看,或者通过引用计数之类的方法),而且对于需要在其他函数中调用的情况,还应该保证mTestProvider为GlobalRef,也就是修改NewObject为NewGlobalRef,但切记在不使用的时候DeleteGlobalRef
这段代码看起来问题还是蛮多的:
"SendJ = (*jniEnv)->GetMethodID(jniEnv, TestProvider, "javaSend","([BI)I");
if(NULL == obdSendJ)return 5;"
这个SendJ和下面的obdSendJ有啥关系?
"if(nativeMethod_firstcall == 1)CtoJavaInit();"
这里面的nativeMethod_firstcall什么时候赋值的?都怎么操作了?
我针对你的需求把你的代码修改了一下,你看看能不能符合要求吧:
static jobject g_testProvider = NULL;
static jmethodID g_sendJ = NULL;
static int g_inited = 0;
int CtoJavaInit(JNIEnv * env)
{
int res = 0;
jmethodID ctrId = NULL;
jclass cls = (*env)->FindClass(env, "com/example/jni/C2jni");
if (NULL == cls)
{
res = 2;
goto end_func;
}
ctrId = (*env)->GetMethodID(env, cls, "<init>", "()V");
if(NULL == ctrId)
{
res = 3;
goto end_func;
}
g_testProvider = (*env)->NewGlobalRef(env, cls, ctrId);
if(NULL == g_testProvider)
{
res = 4;
goto end_func;
}
// 其实javaSend的参数没必要添加长度,Java中数组本身是知道自身长度的
g_sendJ = (*env)->GetMethodID(env, cls, "javaSend","([BI)I");
if(NULL == g_sendJ)
{
res = 5;
goto end_func;
}
end_func:
(*env)->DeleteLocalRef(env, cls);
return res;
}
int cSend(JNIEnv * env, char * data, int datalen)
{
int len, intresult;
jbyteArray bytes = NULL;
if(NULL == g_testProvider || NULL == g_sendJ)
{
return 0;
}
if(NULL == data || datalen > 128)
{
return 0;
}
bytes = (*env)->NewByteArray(env, datalen);
if(NULL == bytes)
{
return 0;
}
(*env)->SetByteArrayRegion(env, bytes, 0, datalen, (const jbyte *)data);
(*env)->CallIntMethod(env, g_testProvider, g_sendJ, bytes, datalen);
(*env)->DeleteLocalRef(env, bytes);
return datalen;
}
JNIEXPORT void JNICALL Java_nativeMethod (JNIEnv * env, jclass thiz)
{
// 这里比较好的做法是将init和cleanup分别在Java端应用开始时和结束时调用,比如onCreate和onDestroy中调用
char *sendtest = "test...";
if (g_inited == 0)
{
CtoJavaInit(env);
g_inited = 1;
}
cSend(env, sendtest, strlen(sendtest));
CtoJavaCleanup(env);
}
void CtoJavaCleanup (JNIEnv * env)
{
if (g_testProvider != NULL)
{
(*env)->DeleteGlobalRef(env, g_testProvider);
g_testProvider = NULL;
}
}
不好意思,上面的代码有些错误:
JNIEXPORT void JNICALL Java_nativeMethod (JNIEnv * env, jclass thiz)问题没解决啊 , 继续请求帮忙 ....
######建议去iteye的高级语言虚拟机群问问######还是喜欢这里,高手啊 ....
还是喜欢这里,高手啊 ....
还是喜欢这里,高手啊 ....
A: java应用
B: java通讯接口
C: JNI中的C接口
C调用B
A循环调用C,N次(200次左右)软件崩溃, 我也崩溃了 ,找不到头绪。。。
宏哥来给你终极解决方案吧
需要和C集成的地方, 用python.
python可以暴露web借口给 java。 其实lua也可以。
jvm是一个平台, 设计到和操作系统直接沟通的地方, 用jni就是自找麻烦。
“ decision over convention, convention over configuration"
这就是为什么要坚持两个凡是的原因
######回复 @郭煜 : android中实现http协议太简单了######用C简单实现一个http协议也是可以的,这么做过,不依赖任何库,代码量也不大,但是是单线程阻塞模型的。版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。